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;
  }
  @Override
  public void onEnable() {

    plugin = this;
    directory = plugin.getDataFolder();
    pdfFile = plugin.getDescription();

    checkEbean();
    setupDatabase();
    setupFiles();
    setupPermissions(); // Smickles thinks this is what we're supposed to do for permissions via
                        // vault
    setupEconomy(); // Smickles thinks this is what we're supposed to do for economy via vault

    logger.info(pdfFile.getName() + " version " + pdfFile.getVersion() + " enabled");
  }
  public boolean marketList(CommandSender sender) {

    List<Commodities> commodities = plugin.getDatabase().find(Commodities.class).findList();

    String list[] = new String[20];
    list[0] = "";
    int row = 0;

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

      // console is 55 characters wide, 20 tall
      list[row] = list[row] + commodities.get(index).getName() + ",  ";

      if (list[row].length() > 55) {

        int split = list[row].lastIndexOf(" ", 54);

        list[row] = list[row].substring(0, split);
        row++;
        if (row > 18) {

          sender.sendMessage("tell smickles that he needs to actually do something about this");
          break;
        }
        list[row] = commodities.get(index).getName() + ",  ";
      }
    }
    list[row] = list[row].substring(0, list[row].lastIndexOf(","));

    // sender.sendMessage(ChatColor.GREEN + "All items on the market");
    for (int x = 0; x <= row; x++) {
      sender.sendMessage(ChatColor.WHITE + list[x]);
    }
    return true;
  }
  public boolean price(CommandSender sender, String item, int amt) {

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

    if (commodity == null) {
      sender.sendMessage(ChatColor.RED + "Invalit commodity name.");
      return false;
    }

    // get the buy and sell price of the item
    Invoice sellPrice = generateInvoice(0, commodity, amt);
    Invoice buyPrice = generateInvoice(1, commodity, amt);

    // send output
    sender.sendMessage(
        ChatColor.GRAY
            + item
            + ChatColor.GREEN
            + " If sold: "
            + ChatColor.WHITE
            + BigDecimal.valueOf(sellPrice.getTotal()).setScale(2, RoundingMode.HALF_UP));
    sender.sendMessage(
        ChatColor.GRAY
            + item
            + ChatColor.GREEN
            + " If bought: "
            + ChatColor.WHITE
            + BigDecimal.valueOf(buyPrice.getTotal()).setScale(2, RoundingMode.HALF_UP));
    return true;
  }
  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);
  }
  public boolean sellAll(Player player) {

    // make a list of all commodities
    List<Commodities> commodities = plugin.getDatabase().find(Commodities.class).findList();

    // run thru each slot in the player's inventory for commodities
    int index = 0;
    BigDecimal sale = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);

    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(index);
      int slotId = slot.getTypeId();
      BigDecimal slotAmount = new BigDecimal(slot.getAmount()).setScale(0, RoundingMode.HALF_UP);

      Byte slotByteData = Byte.valueOf("0");
      try {
        slotByteData = slot.getData().getData();
      } catch (NullPointerException e) {
        slotByteData = Byte.valueOf("0");
      }

      for (int x = 0; x < commodities.size(); x++) {

        if ((commodities.get(x).getNumber() == slotId)
            && (Byte.valueOf(String.valueOf(commodities.get(x).getData())).compareTo(slotByteData)
                == 0)) {

          Invoice thisSale =
              generateInvoice(
                  0, // perform sale of this slot
                  commodities.get(x),
                  slotAmount.intValue());
          sale = sale.add(BigDecimal.valueOf(thisSale.getTotal())); // rack up our total

          // save the new value
          commodities.get(x).setValue(thisSale.getValue());
          plugin.getDatabase().save(commodities.get(x));

          player.getInventory().clear(index); // remove the item(s)
          economy.depositPlayer(
              player.getName(), // "pay the man"
              thisSale.getTotal());

          // give nice output
          player.sendMessage(
              ChatColor.GREEN
                  + "Sold "
                  + ChatColor.WHITE
                  + slotAmount
                  + " "
                  + ChatColor.GRAY
                  + commodities.get(x).getName()
                  + ChatColor.GREEN
                  + " for "
                  + ChatColor.WHITE
                  + BigDecimal.valueOf(thisSale.getTotal()).setScale(2, RoundingMode.HALF_UP));
          break;
        }
      }
      index++;
    }

    // give a nice total column
    if (sale == BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP))
      player.sendMessage("Nothing to Sell");
    player.sendMessage(ChatColor.GREEN + "--------------------------------");
    player.sendMessage(
        ChatColor.GREEN
            + "Total Sale: "
            + ChatColor.WHITE
            + sale.setScale(2, RoundingMode.HALF_UP));
    return true;
  }
  /**
   * 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;
    }
  }
  /** use this in the case that we need to update from the old way of storing data in config.yml */
  @SuppressWarnings("deprecation")
  private void switchToDatabase() {

    logger.info("[" + pdfFile.getName() + "] Converting flatfile to database...");

    // load old config file
    org.bukkit.configuration.Configuration items = plugin.getConfig();

    // populate the database with existing values
    logger.info("[" + plugin.getDescription().getName() + "] Populating database ...");
    for (String item : items.getKeys(false)) {

      Commodities commodity =
          plugin
              .getDatabase()
              .find(Commodities.class)
              .where()
              .ieq("name", item)
              .ieq("number", items.getString(item + ".number"))
              .findUnique();

      if (commodity == null) {

        commodity = new Commodities();
        commodity.setName(item);

        for (String key : items.getConfigurationSection(item).getKeys(false)) {

          String value = items.getString(item + "." + key);

          if (key.equalsIgnoreCase("value")) commodity.setValue(Double.valueOf(value));
          if (key.equalsIgnoreCase("number")) commodity.setNumber(Integer.valueOf(value));
          if (key.equalsIgnoreCase("minValue")) commodity.setMinValue(Double.valueOf(value));
          if (key.equalsIgnoreCase("maxValue")) commodity.setMaxValue(Double.valueOf(value));
          if (key.equalsIgnoreCase("changeRate")) commodity.setChangeRate(Double.valueOf(value));
          if (key.equalsIgnoreCase("data")) commodity.setData(Integer.valueOf(value));
          if (key.equalsIgnoreCase("spread")) commodity.setSpread(Double.valueOf(value));
        }
      } else {
        logger.warning(
            "["
                + pdfFile.getName()
                + "] Duplicate commodity found, that can't be good. You may want to restore the config.yml backup, delete Dynamark.db (or equivilant), then check the file for commodities with the same \"number\", correct the issue, and then restart your server to try again.");
        continue;
      }

      plugin.getDatabase().save(commodity);
      commodity = null;
    }

    // mv config.yml to config.yml.bak
    logger.info("[" + plugin.getDescription().getName() + "] backing up config.yml...");

    File configFlatFile = new File(directory + File.separator + "config.yml");
    File backupName = new File(directory + File.separator + "config.yml.bak");

    configFlatFile.renameTo(backupName);

    //  rm config.yml.example
    File toDelete = new File(directory + File.separator + "config.yml.EXAMPLE");

    toDelete.delete();

    logger.info(
        "[" + plugin.getDescription().getName() + "] Successfully converted flatfile to database");
  }