package tc.oc.pgm.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.MaterialData;
import tc.oc.commons.core.inspect.Inspectable;
/**
* A pattern that matches a specific Material and optionally, its
* metadata/damage value. If constructed without the data value, the
* pattern will match only on the Material and ignore the metadata/damage.
* If constructed with a data value, the pattern will only match materials
* with that metadata/damage value. In the latter case, Materials passed
* to the match() method will be assumed to have a data value of 0,
* and will only match if 0 was also passed to the constructor.
*
* The rationale is that only materials that don't use their data value for
* identity will be passed to the matches() method as Materials, and if the
* pattern is looking for a non-zero data on such a material, it must be
* looking for a particular non-default state and thus should not match the
* default state.
*
* TODO: rename MaterialMatcher to MaterialPattern, and this class to something like SingleMaterialPattern
*/
public class MaterialPattern extends Inspectable.Impl implements MaterialMatcher {
private final @Inspect Material material;
private final @Inspect Optional<Byte> data;
public MaterialPattern(Material material, byte data) {
this.material = material;
this.data = Optional.of(data);
}
public MaterialPattern(MaterialData materialData) {
this.material = materialData.getItemType();
this.data = Optional.of(materialData.getData());
}
public MaterialPattern(Material material) {
this.material = material;
this.data = Optional.empty();
}
public Material getMaterial() {
return this.material;
}
@Override
public Collection<Material> getMaterials() {
return Collections.singleton(getMaterial());
}
public MaterialData getMaterialData() {
return material.getNewData(data.orElse((byte) 0));
}
public boolean dataMatters() {
return data.isPresent();
}
@Override
public boolean matches(Material material) {
return material == this.material &&
(!data.isPresent() || data.get() == 0);
}
@Override
public boolean matches(MaterialData materialData) {
return materialData.getItemType() == this.material &&
(!data.isPresent() || data.get() == materialData.getData());
}
@Override
public boolean matches(ItemStack stack) {
return stack.getType() == this.material &&
(!data.isPresent() || data.get() == stack.getData().getData());
}
public static MaterialPattern accepting(Material material) {
return new MaterialPattern(material);
}
public static MaterialPattern parse(String text) {
String[] pieces = text.split(":");
Material material = Material.matchMaterial(pieces[0]);
if(material == null) {
throw new IllegalArgumentException("Could not find material '" + pieces[0] + "'.");
}
if(pieces.length > 1) {
try {
return new MaterialPattern(material, Byte.parseByte(pieces[1]));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid damage value: " + pieces[1], e);
}
} else {
return new MaterialPattern(material);
}
}
public static List<MaterialPattern> fromMaterials(Collection<Material> materials) {
List<MaterialPattern> patterns = new ArrayList<>(materials.size());
for(Material material : materials) {
patterns.add(new MaterialPattern(material));
}
return patterns;
}
public static List<MaterialPattern> fromMaterialDatas(Collection<MaterialData> materials) {
List<MaterialPattern> patterns = new ArrayList<>(materials.size());
for(MaterialData material : materials) {
patterns.add(new MaterialPattern(material));
}
return patterns;
}
}