public boolean marketBottom(CommandSender sender) {

    // gather the list of commodities
    List<Commodities> commodities = plugin.getDatabase().find(Commodities.class).findList();

    // sort 'em and return only the top 10
    List<Commodities> top10 =
        plugin
            .getDatabase()
            .filter(Commodities.class)
            .sort("value asc")
            .maxRows(10)
            .filter(commodities);

    // calculate elasticity
    List<Integer> elasticities = new LinkedList<Integer>();

    for (int index = 0; index < top10.size(); index++) {

      Commodities c = top10.get(index);
      double value = c.getValue();
      double changeRate = c.getChangeRate();
      double minValue = c.getMinValue();
      if (value < minValue) {

        double newValue = Math.abs(value - minValue);
        double elasticity = (newValue / changeRate);
        int el = (int) Math.round(elasticity);

        elasticities.add(index, el);
        c.setValue(minValue);
      } else {
        elasticities.add(index, 0);
      }
    }

    // Send them to the player
    for (int x = 0; x < top10.size(); x++) {
      int rank = x + 1;

      sender.sendMessage(
          ChatColor.GREEN
              + String.valueOf(rank)
              + ". "
              + ChatColor.WHITE
              + top10.get(x).getName()
              + " "
              + ChatColor.GRAY
              + top10.get(x).getValue()
              + " "
              + ChatColor.DARK_GREEN
              + elasticities.get(x));
    }

    return true;
  }
  /**
   * Determine the cost of a given number of an item and calculate a new value for the item
   * accordingly.
   *
   * @param oper 1 for buying, 0 for selling.
   * @param commodity the commodity in question
   * @param amount the desired amount of the item in question
   * @return the total cost and the calculated new value as an Invoice
   */
  public Invoice generateInvoice(int oper, Commodities commodity, int amount) {

    // get the initial value of the item, 0 for not found
    Invoice inv = new Invoice(0.0, 0.0);
    inv.value = commodity.getValue();

    // get the spread so we can do one initial decrement of the value if we are selling
    BigDecimal spread = BigDecimal.valueOf(commodity.getSpread());

    // determine the total cost
    inv.total = 0.0;

    for (int x = 1; x <= amount; x++) {
      BigDecimal minValue = BigDecimal.valueOf(commodity.getMinValue());
      BigDecimal maxValue = BigDecimal.valueOf(commodity.getMaxValue());
      BigDecimal changeRate = BigDecimal.valueOf(commodity.getChangeRate());

      // work the spread on the first one.
      if ((oper == 0) && (x == 1)) {
        inv.subtractValue(spread.doubleValue());
      } else if ((oper == 0) && (x > 1)) { // otherwise, do the usual decriment.
        inv.subtractValue(changeRate.doubleValue());
      }

      // check the current value
      if (inv.getValue() >= minValue.doubleValue()) { // current value is @ or above minValue
        // be sure value is not above maxValue
        if (inv.getValue() < maxValue.doubleValue()) { // current value is "just right"
          inv.addTotal(inv.getValue()); // add current value to total
        } else { // current value is above the max
          inv.addTotal(maxValue.doubleValue()); // add maxValue to total
        }
      } else { // current value is below the minimum

        inv.addTotal(minValue.doubleValue()); // add the minimum to total

        if ((oper == 0) && (x == 1)) {
          inv.subtractTotal(
              spread
                  .doubleValue()); // subtract the spread if we're selling and this is the first run
        }
      }

      // Change our stored value for the item
      // we don't care about min/maxValue here because we don't want the value to 'bounce' off of
      // them.
      if (oper == 1) {
        inv.addValue(changeRate.doubleValue());
      }
    }
    return inv;
  }
  public BigDecimal price(String item) {

    // retrieve the commodity in question
    Commodities commodity =
        plugin.getDatabase().find(Commodities.class).where().ieq("name", item).findUnique();

    if (commodity == null) return null;

    double price = commodity.getValue();
    double minValue = commodity.getMinValue();
    double maxValue = commodity.getMaxValue();

    if (price > maxValue) return BigDecimal.valueOf(maxValue).setScale(2, RoundingMode.HALF_UP);
    if (price < minValue) return BigDecimal.valueOf(minValue).setScale(2, RoundingMode.HALF_UP);
    return BigDecimal.valueOf(price).setScale(2, RoundingMode.HALF_UP);
  }
  /**
   * Sell a specified amount of an item for the player.
   *
   * @param player The player on behalf of which these actions will be carried out.
   * @param item The desired item in the form of the item name.
   * @param amount The desired amount of the item to sell.
   * @return true on success, false on failure.
   */
  public boolean sell(Player player, String item, int amount) {

    // Be sure we have a positive amount
    if (amount < 1) {
      player.sendMessage(ChatColor.RED + "Invalid amount.");
      player.sendMessage("No negative numbers or zero, please.");
      return false;
    }

    // retrieve the commodity in question
    Commodities commodity =
        plugin.getDatabase().find(Commodities.class).where().ieq("name", item).findUnique();

    if (commodity == null) {
      player.sendMessage(ChatColor.RED + "Not allowed to buy that item.");
      player.sendMessage("Be sure you typed the correct name");
      return false;
    }

    // determine what it will pay
    Invoice invoice = generateInvoice(0, commodity, amount);

    // If the player has enough of the item, perform the transaction.
    int id = commodity.getNumber();
    Byte byteData = Byte.valueOf(String.valueOf(commodity.getData()));

    ItemStack its = new ItemStack(id, amount, (short) 0, byteData);

    if (player.getInventory().contains(id)) {

      // Figure out how much is left over
      int left = getAmountInInventory(player, its) - amount;

      if (left < 0) { // this indicates the correct id, but the wrong bytedata value
        // give nice output even if they gave a bad name.
        player.sendMessage(ChatColor.RED + "You don't have enough " + item);
        player.sendMessage(
            ChatColor.GREEN
                + "In Inventory: "
                + ChatColor.WHITE
                + getAmountInInventory(player, its));
        player.sendMessage(ChatColor.GREEN + "Attempted Amount: " + ChatColor.WHITE + amount);
        return false;
      }

      // Take out all of the item
      int x = 0;

      for (@SuppressWarnings("unused")
      ItemStack stack :
          player
              .getInventory()
              .getContents()) { // we do it this way incase a user has an expanded inventory via
                                // another plugin

        ItemStack slot = player.getInventory().getItem(x);

        if (slot != null) {
          Byte slotData = Byte.valueOf("0");

          try {
            slotData = slot.getData().getData();
          } catch (NullPointerException e) {
          }

          if ((slot.getTypeId() == id) && (slotData.compareTo(byteData) == 0)) {
            player.getInventory().clear(x);
          }
        }
        x++;
      }

      // put back what was left over
      if (left > 0) {
        ItemStack itsLeft = its;
        itsLeft.setAmount(left);
        player.getInventory().addItem(itsLeft);
      }

      // record the change in value
      commodity.setValue(invoice.getValue());
      plugin.getDatabase().save(commodity);

      // use BigDecimal to format value for output
      double v = commodity.getValue();
      double max = commodity.getMaxValue();
      double min = commodity.getMinValue();
      BigDecimal value;
      if (v < max && v > min) {
        value = BigDecimal.valueOf(v).setScale(2, RoundingMode.HALF_UP);
      } else if (v <= min) {
        value = BigDecimal.valueOf(min).setScale(2, RoundingMode.HALF_UP);
      } else {
        value = BigDecimal.valueOf(max).setScale(2, RoundingMode.HALF_UP);
      }
      BigDecimal spread = BigDecimal.valueOf(commodity.getSpread());

      // give some nice output
      BigDecimal sale =
          BigDecimal.valueOf((invoice.getTotal() + spread.doubleValue()))
              .setScale(2, RoundingMode.HALF_UP);

      player.sendMessage(ChatColor.GREEN + "--------------------------------");
      player.sendMessage(
          ChatColor.GREEN
              + "Old Balance: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(economy.getBalance(player.getName()))
                  .setScale(2, RoundingMode.HALF_UP));

      // deposit the money
      economy.depositPlayer(player.getName(), invoice.getTotal());

      player.sendMessage(ChatColor.GREEN + "Sale: " + ChatColor.WHITE + sale);
      player.sendMessage(ChatColor.GREEN + "Selling Fee: " + ChatColor.WHITE + spread);
      player.sendMessage(ChatColor.GREEN + "--------------------------------");
      player.sendMessage(
          ChatColor.GREEN
              + "Net Gain: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(invoice.getTotal()).setScale(2, RoundingMode.HALF_UP));
      player.sendMessage(
          ChatColor.GREEN
              + "New Balance: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(economy.getBalance(player.getName()))
                  .setScale(2, RoundingMode.HALF_UP));
      player.sendMessage(ChatColor.GREEN + "--------------------------------");
      player.sendMessage(
          ChatColor.GRAY + item + ChatColor.GREEN + " New Price: " + ChatColor.WHITE + value);
      return true;
    } else { // give nice output even if they gave a bad number.

      player.sendMessage(ChatColor.RED + "You don't have enough " + item);
      player.sendMessage(
          ChatColor.GREEN + "In Inventory: " + ChatColor.WHITE + getAmountInInventory(player, its));
      player.sendMessage(ChatColor.GREEN + "Attempted Amount: " + ChatColor.WHITE + amount);
      return false;
    }
  }
  /**
   * Buy a specified amount of an item for the player.
   *
   * @param player The player on behalf of which these actions will be carried out.
   * @param item The desired item in the form of the item name.
   * @param amount The desired amount of the item to purchase.
   * @return true on success, false on failure.
   */
  public boolean buy(Player player, String item, int amount) {

    // Be sure we have a positive amount
    if (amount < 1) {
      player.sendMessage(ChatColor.RED + "Invalid amount.");
      player.sendMessage("No negative numbers or zero, please.");
      return false;
    }

    // retrieve the commodity in question
    Commodities commodity =
        plugin.getDatabase().find(Commodities.class).where().ieq("name", item).findUnique();

    // check that we found something
    if (commodity == null) {
      player.sendMessage(ChatColor.RED + "Not allowed to buy that item.");
      player.sendMessage("Be sure you typed the correct name");
      return false;
    }

    // determine what it will cost
    Invoice invoice = generateInvoice(1, commodity, amount);

    // check the player's wallet
    if (economy.has(player.getName(), invoice.getTotal())) {

      // give 'em the items and drop any extra
      Byte byteData = Byte.valueOf(String.valueOf(commodity.getData()));
      int id = commodity.getNumber();

      HashMap<Integer, ItemStack> overflow =
          player.getInventory().addItem(new ItemStack(id, amount, (short) 0, byteData));
      for (int a : overflow.keySet()) {
        player.getWorld().dropItem(player.getLocation(), overflow.get(a));
      }

      // save the new value
      commodity.setValue(invoice.getValue());
      getDatabase().save(commodity);

      // use BigDecimal to format value for output
      double v = commodity.getValue();
      double max = commodity.getMaxValue();
      double min = commodity.getMinValue();
      BigDecimal value;
      if (v < max && v > min) {
        value = BigDecimal.valueOf(v).setScale(2, RoundingMode.HALF_UP);
      } else if (v <= min) {
        value = BigDecimal.valueOf(min).setScale(2, RoundingMode.HALF_UP);
      } else {
        value = BigDecimal.valueOf(max).setScale(2, RoundingMode.HALF_UP);
      }

      // Give some nice output.
      player.sendMessage(ChatColor.GREEN + "--------------------------------");
      player.sendMessage(
          ChatColor.GREEN
              + "Old Balance: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(economy.getBalance(player.getName()))
                  .setScale(2, RoundingMode.HALF_UP));
      // Subtract the invoice (this is an efficient place to do this)
      economy.withdrawPlayer(player.getName(), invoice.getTotal());

      player.sendMessage(
          ChatColor.GREEN
              + "Cost: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(invoice.getTotal()).setScale(2, RoundingMode.HALF_UP));
      player.sendMessage(
          ChatColor.GREEN
              + "New Balance: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(economy.getBalance(player.getName()))
                  .setScale(2, RoundingMode.HALF_UP));
      player.sendMessage(ChatColor.GREEN + "--------------------------------");
      player.sendMessage(
          ChatColor.GRAY + item + ChatColor.GREEN + " New Price: " + ChatColor.WHITE + value);
      return true;
    } else { // Otherwise, give nice output anyway ;)

      // The idea here is to show how much more money is needed.
      BigDecimal difference =
          BigDecimal.valueOf(economy.getBalance(player.getName()) - invoice.getTotal())
              .setScale(2, RoundingMode.HALF_UP);
      player.sendMessage(ChatColor.RED + "You don't have enough money");
      player.sendMessage(
          ChatColor.GREEN
              + "Balance: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(economy.getBalance(player.getName()))
                  .setScale(2, RoundingMode.HALF_UP));
      player.sendMessage(
          ChatColor.GREEN
              + "Cost: "
              + ChatColor.WHITE
              + BigDecimal.valueOf(invoice.getTotal()).setScale(2, RoundingMode.HALF_UP));
      player.sendMessage(ChatColor.GREEN + "Difference: " + ChatColor.RED + difference);
      return true;
    }
  }