package org.mctourney.autoreferee.listeners;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.MapDifference;
import com.google.common.collect.MapDifference.ValueDifference;
import com.google.common.collect.Maps;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.block.Block;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.mctourney.autoreferee.util.BlockData;
@SuppressWarnings("serial")
public class GoalsInventorySnapshot extends HashMap<BlockData, Integer>
{
public GoalsInventorySnapshot()
{
super();
}
public GoalsInventorySnapshot(ItemStack item, Set<BlockData> goals)
{
super();
BlockData target = BlockData.fromItemStack(item);
for (BlockData goal : goals)
if (goal.equals(target))
this.put(goal, item.getAmount());
}
public GoalsInventorySnapshot(ItemStack item, BlockData goal)
{
super();
if (goal.equals(BlockData.fromItemStack(item)))
this.put(goal, item.getAmount());
}
public static GoalsInventorySnapshot fromItemsAndGoals(Collection<ItemStack> items, Set<BlockData> goals)
{
GoalsInventorySnapshot ret = new GoalsInventorySnapshot();
for (BlockData goal : goals)
{
int count = itemSum(goal, items);
ret.put(goal, count);
}
return ret;
}
public GoalsInventorySnapshot(Inventory inv, Set<BlockData> goals)
{
super();
ItemStack[] contents = inv.getContents();
for (BlockData goal : goals)
{
int count = itemSum(goal, contents);
this.put(goal, count);
}
}
public GoalsInventorySnapshot(Collection<Block> blocks, Set<BlockData> goals)
{
super();
for (BlockData goal : goals)
{
int count = blockCount(goal, blocks);
this.put(goal, count);
}
}
public GoalsInventorySnapshot(MapDifference<BlockData, Integer> diff)
{
super();
this.putAll(diff.entriesOnlyOnLeft());
for (Map.Entry<BlockData, Integer> entry : diff.entriesOnlyOnRight().entrySet())
{
this.put(entry.getKey(), -entry.getValue());
}
for (Map.Entry<BlockData, ValueDifference<Integer>> entry : diff.entriesDiffering().entrySet())
{
this.put(entry.getKey(), entry.getValue().leftValue() - entry.getValue().rightValue());
}
}
public static GoalsInventorySnapshot fromDiff(MapDifference<BlockData, Integer> diff, boolean leftSideOnly)
{
GoalsInventorySnapshot snap = new GoalsInventorySnapshot();
if (leftSideOnly)
snap.putAll(diff.entriesOnlyOnLeft());
else
snap.putAll(diff.entriesOnlyOnRight());
// Only positive differences
for (Map.Entry<BlockData, ValueDifference<Integer>> entry : diff.entriesDiffering().entrySet())
{
int count;
if (leftSideOnly)
count = entry.getValue().leftValue() - entry.getValue().rightValue();
else
count = entry.getValue().rightValue() - entry.getValue().leftValue();
if (count > 0)
snap.put(entry.getKey(), count);
}
return snap;
}
public int getInt(BlockData key)
{
Integer val = get(key);
if (val == null) return 0;
return val;
}
@Override
public Integer put(BlockData key, Integer value)
{
Validate.notNull(value, "Null integers are not permitted in GoalsInventorySnapshot");
// Convert all zeros to not-present
if (value == 0)
return this.remove(key);
return super.put(key, value);
}
/**
* This object is left in the return, the provided argument is the right.
*/
public MapDifference<BlockData, Integer> getDiff(GoalsInventorySnapshot other)
{
return Maps.difference(this, other);
}
public void addInPlace(GoalsInventorySnapshot other)
{
for (Map.Entry<BlockData, Integer> entry : other.entrySet())
addInPlace(entry.getKey(), entry.getValue());
}
public void addInPlace(BlockData key, Integer value)
{
Validate.notNull(value);
put(key, getInt(key) + value);
}
public void subtractInPlace(GoalsInventorySnapshot other)
{
for (Map.Entry<BlockData, Integer> entry : other.entrySet())
subtractInPlace(entry.getKey(), entry.getValue());
}
public void subtractInPlace(BlockData key, Integer value)
{
Validate.notNull(value);
put(key, getInt(key) - value);
}
private static int itemSum(BlockData data, ItemStack[] items)
{
int count = 0;
for (ItemStack it : items)
{
if (it == null) continue;
if (data.equals(BlockData.fromItemStack(it)))
count += it.getAmount();
}
return count;
}
private static int itemSum(BlockData data, Collection<ItemStack> items)
{
int count = 0;
for (ItemStack it : items)
{
if (it == null) continue;
if (data.equals(BlockData.fromItemStack(it)))
count += it.getAmount();
}
return count;
}
private static int blockCount(BlockData data, Collection<Block> blocks)
{
int count = 0;
for (Block block : blocks)
{
if (data.matchesBlock(block))
count++;
}
return count;
}
public String toString()
{
if (this.isEmpty()) return "";
StringBuilder sb = new StringBuilder();
boolean first = true;
// Desired output: RED WOOL, GREEN WOOL, 5 x YELLOW WOOL, 20 x BLUE WOOL
for (Map.Entry<BlockData, Integer> entry : this.entrySet())
{
if (!first)
{ sb.append(", "); }
else
{ first = false; }
int count = entry.getValue();
if (count != 1)
sb.append(ChatColor.YELLOW).append(Integer.toString(count)).append(" x ").append(ChatColor.RESET);
sb.append(entry.getKey().getDisplayName());
sb.append(ChatColor.RESET);
}
return sb.toString();
}
}