// Path: SaneEconomySignShop/src/main/java/org/appledash/saneeconomysignshop/signshop/ShopTransaction.java
// public class ShopTransaction {
//     private final Currency currency;
//     // Direction is always what the player is doing. BUY = player is buying from shop.
//     private final TransactionDirection direction;
//     private final Player player;
//     private final ItemInfo item;
//     private final int quantity;
//     private final BigDecimal price;
// 
//     public ShopTransaction(Currency currency, TransactionDirection direction, Player player, ItemInfo item, int quantity, BigDecimal price) {
//         this.currency = currency;
//         this.direction = direction;
//         this.player = player;
//         this.item = item;
//         this.quantity = quantity;
//         this.price = price;
//     }
// 
//     public TransactionDirection getDirection() {
//         return this.direction;
//     }
// 
//     public Player getPlayer() {
//         return this.player;
//     }
// 
//     public ItemInfo getItem() {
//         return this.item;
//     }
// 
//     public int getQuantity() {
//         return this.quantity;
//     }
// 
//     public BigDecimal getPrice() {
//         return this.price;
//     }
// 
//     public Transaction makeEconomyTransaction() {
//         if (this.direction == TransactionDirection.BUY) {
//             return new Transaction(this.currency, Economable.wrap(this.player), Economable.PLUGIN, this.price, TransactionReason.PLUGIN_TAKE);
//         } else {
//             return new Transaction(this.currency, Economable.PLUGIN, Economable.wrap(this.player), this.price, TransactionReason.PLUGIN_GIVE);
//         }
//     }
// 
//     public enum TransactionDirection {
//         BUY, SELL
//     }
// }
// 
// Path: SaneEconomySignShop/src/main/java/org/appledash/saneeconomysignshop/signshop/ShopTransaction.java
// public enum TransactionDirection {
//     BUY, SELL
// }
// 
// Path: SaneEconomySignShop/src/main/java/org/appledash/saneeconomysignshop/util/ItemDatabase.java
// public static class InvalidItemException extends Exception {
//     public InvalidItemException(String message) {
//         super(message);
//     }
// }


import org.appledash.saneeconomysignshop.signshop.ShopTransaction;
import org.appledash.saneeconomysignshop.signshop.ShopTransaction.TransactionDirection;
import org.appledash.saneeconomysignshop.util.ItemDatabase.InvalidItemException;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
package org.appledash.saneeconomysignshop.util;



/**
 * Created by appledash on 1/1/17.
 * Blackjack is still best pony.
 */
public class LimitManager {
    private static final Logger LOGGER = Logger.getLogger("LimitManager");
    // private final Map<ItemInfo, ItemLimits> buyItemLimits = new DefaultHashMap<ItemInfo, ItemLimits>(() -> ItemLimits.DEFAULT);
    private final Map<ItemInfo, ItemLimits> sellItemLimits = new DefaultHashMap<>(() -> ItemLimits.DEFAULT);
    @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
    private final Map<UUID, Map<ItemInfo, Integer>> sellPlayerLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>((info) -> this.sellItemLimits.get(info).getLimit()));
    // private final Map<TransactionDirection, Map<ItemInfo, ItemLimits>> itemLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> ItemLimits.DEFAULT));
    // This is a slightly complex data structure. It works like this:
    // It's a map of (limit types to (maps of players to (maps of materials to the remaining limit))).
    // All the TransactionDirections defaults to an empty map, which defaults to an empty map, which defaults to 0.
    // @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
    // private final Map<TransactionDirection, Map<UUID, Map<ItemInfo, Integer>>> playerLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> 0)));

    public int getRemainingLimit(Player player, TransactionDirection type, ItemInfo stack) {
        if (type == TransactionDirection.SELL) {
            return this.sellPlayerLimits.get(player.getUniqueId()).get(stack);
        }

        throw new IllegalArgumentException("Don't know how to get limits for that TransactionDirection!");
    }

    public void setRemainingLimit(Player player, TransactionDirection type, ItemInfo stack, int limit) {
        if (type == TransactionDirection.SELL) {
            if (this.sellPlayerLimits.get(player.getUniqueId()).get(stack) == -1) {
                return;
            }

            limit = Math.min(limit, this.sellItemLimits.get(stack).getLimit());
            limit = Math.max(0, limit);

            this.sellPlayerLimits.get(player.getUniqueId()).put(stack, limit);
            return;
        }

        throw new IllegalArgumentException("Don't know how to set limits for that TransactionDirection!");
    }

    public boolean shouldAllowTransaction(ShopTransaction transaction) {
        // System.out.printf("Limit: %d, quantity: %d\n", limit, transaction.getQuantity());
        return this.getRemainingLimit(transaction.getPlayer(), transaction.getDirection(), transaction.getItem()) >= transaction.getQuantity();
    }

    public void incrementLimitsHourly() {
        // For every limit type
        // For every player
        // For every limit
        // Increment limit by the limit for the specific direction and item.

        this.sellPlayerLimits.forEach((playerUuid, itemToLimit) -> {
            Map<ItemInfo, Integer> newLimits = new HashMap<>();

// Path: SaneEconomySignShop/src/main/java/org/appledash/saneeconomysignshop/signshop/ShopTransaction.java
// public class ShopTransaction {
//     private final Currency currency;
//     // Direction is always what the player is doing. BUY = player is buying from shop.
//     private final TransactionDirection direction;
//     private final Player player;
//     private final ItemInfo item;
//     private final int quantity;
//     private final BigDecimal price;
// 
//     public ShopTransaction(Currency currency, TransactionDirection direction, Player player, ItemInfo item, int quantity, BigDecimal price) {
//         this.currency = currency;
//         this.direction = direction;
//         this.player = player;
//         this.item = item;
//         this.quantity = quantity;
//         this.price = price;
//     }
// 
//     public TransactionDirection getDirection() {
//         return this.direction;
//     }
// 
//     public Player getPlayer() {
//         return this.player;
//     }
// 
//     public ItemInfo getItem() {
//         return this.item;
//     }
// 
//     public int getQuantity() {
//         return this.quantity;
//     }
// 
//     public BigDecimal getPrice() {
//         return this.price;
//     }
// 
//     public Transaction makeEconomyTransaction() {
//         if (this.direction == TransactionDirection.BUY) {
//             return new Transaction(this.currency, Economable.wrap(this.player), Economable.PLUGIN, this.price, TransactionReason.PLUGIN_TAKE);
//         } else {
//             return new Transaction(this.currency, Economable.PLUGIN, Economable.wrap(this.player), this.price, TransactionReason.PLUGIN_GIVE);
//         }
//     }
// 
//     public enum TransactionDirection {
//         BUY, SELL
//     }
// }
// 
// Path: SaneEconomySignShop/src/main/java/org/appledash/saneeconomysignshop/signshop/ShopTransaction.java
// public enum TransactionDirection {
//     BUY, SELL
// }
// 
// Path: SaneEconomySignShop/src/main/java/org/appledash/saneeconomysignshop/util/ItemDatabase.java
// public static class InvalidItemException extends Exception {
//     public InvalidItemException(String message) {
//         super(message);
//     }
// }


// Path: SaneEconomySignShop/src/main/java/org/appledash/saneeconomysignshop/util/LimitManager.java
import org.appledash.saneeconomysignshop.signshop.ShopTransaction;
import org.appledash.saneeconomysignshop.signshop.ShopTransaction.TransactionDirection;
import org.appledash.saneeconomysignshop.util.ItemDatabase.InvalidItemException;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;

package org.appledash.saneeconomysignshop.util;



/**
 * Created by appledash on 1/1/17.
 * Blackjack is still best pony.
 */
public class LimitManager {
    private static final Logger LOGGER = Logger.getLogger("LimitManager");
    // private final Map<ItemInfo, ItemLimits> buyItemLimits = new DefaultHashMap<ItemInfo, ItemLimits>(() -> ItemLimits.DEFAULT);
    private final Map<ItemInfo, ItemLimits> sellItemLimits = new DefaultHashMap<>(() -> ItemLimits.DEFAULT);
    @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
    private final Map<UUID, Map<ItemInfo, Integer>> sellPlayerLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>((info) -> this.sellItemLimits.get(info).getLimit()));
    // private final Map<TransactionDirection, Map<ItemInfo, ItemLimits>> itemLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> ItemLimits.DEFAULT));
    // This is a slightly complex data structure. It works like this:
    // It's a map of (limit types to (maps of players to (maps of materials to the remaining limit))).
    // All the TransactionDirections defaults to an empty map, which defaults to an empty map, which defaults to 0.
    // @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
    // private final Map<TransactionDirection, Map<UUID, Map<ItemInfo, Integer>>> playerLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> 0)));

    public int getRemainingLimit(Player player, TransactionDirection type, ItemInfo stack) {
        if (type == TransactionDirection.SELL) {
            return this.sellPlayerLimits.get(player.getUniqueId()).get(stack);
        }

        throw new IllegalArgumentException("Don't know how to get limits for that TransactionDirection!");
    }

    public void setRemainingLimit(Player player, TransactionDirection type, ItemInfo stack, int limit) {
        if (type == TransactionDirection.SELL) {
            if (this.sellPlayerLimits.get(player.getUniqueId()).get(stack) == -1) {
                return;
            }

            limit = Math.min(limit, this.sellItemLimits.get(stack).getLimit());
            limit = Math.max(0, limit);

            this.sellPlayerLimits.get(player.getUniqueId()).put(stack, limit);
            return;
        }

        throw new IllegalArgumentException("Don't know how to set limits for that TransactionDirection!");
    }

    public boolean shouldAllowTransaction(ShopTransaction transaction) {
        // System.out.printf("Limit: %d, quantity: %d\n", limit, transaction.getQuantity());
        return this.getRemainingLimit(transaction.getPlayer(), transaction.getDirection(), transaction.getItem()) >= transaction.getQuantity();
    }

    public void incrementLimitsHourly() {
        // For every limit type
        // For every player
        // For every limit
        // Increment limit by the limit for the specific direction and item.

        this.sellPlayerLimits.forEach((playerUuid, itemToLimit) -> {
            Map<ItemInfo, Integer> newLimits = new HashMap<>();

            itemToLimit.forEach((itemInfo, currentLimit) ->