package net.glowstone.util.nbt;
import org.apache.commons.lang3.Validate;
import java.lang.reflect.Constructor;
import java.util.*;
/**
* The {@code TAG_Compound} tag.
*/
public final class CompoundTag extends Tag<Map<String, Tag>> {
/**
* The value.
*/
private final Map<String, Tag> value = new LinkedHashMap<>();
/**
* Creates a new, empty CompoundTag.
*/
public CompoundTag() {
super(TagType.COMPOUND);
}
@Override
public Map<String, Tag> getValue() {
return value;
}
@Override
protected void valueToString(StringBuilder bldr) {
bldr.append(value.size()).append(" entries\n{\n");
for (Map.Entry<String, Tag> entry : value.entrySet()) {
bldr.append(" ").append(entry.getKey()).append(": ").append(entry.getValue().toString().replaceAll("\n", "\n ")).append("\n");
}
bldr.append("}");
}
////////////////////////////////////////////////////////////////////////////
// Helper stuff
public boolean isEmpty() {
return value.isEmpty();
}
/**
* Check if the compound contains the given key.
* @param key The key.
* @return True if the key is in the map.
*/
public boolean containsKey(String key) {
return value.containsKey(key);
}
public void remove(String key) {
value.remove(key);
}
////////////////////////////////////////////////////////////////////////////
// Simple gets
public boolean getBool(String key) {
return get(key, ByteTag.class) != 0;
}
public byte getByte(String key) {
return get(key, ByteTag.class);
}
public short getShort(String key) {
return get(key, ShortTag.class);
}
public int getInt(String key) {
return get(key, IntTag.class);
}
public long getLong(String key) {
return get(key, LongTag.class);
}
public float getFloat(String key) {
return get(key, FloatTag.class);
}
public double getDouble(String key) {
return get(key, DoubleTag.class);
}
public byte[] getByteArray(String key) {
return get(key, ByteArrayTag.class);
}
public String getString(String key) {
return get(key, StringTag.class);
}
public int[] getIntArray(String key) {
return get(key, IntArrayTag.class);
}
////////////////////////////////////////////////////////////////////////////
// Fancy gets
@SuppressWarnings("unchecked")
public <V> List<V> getList(String key, TagType type) {
List<? extends Tag> original = getTagList(key, type);
List<V> result = new ArrayList<>(original.size());
for (Tag item : original) {
result.add((V) item.getValue());
}
return result;
}
public CompoundTag getCompound(String key) {
return getTag(key, CompoundTag.class);
}
@SuppressWarnings("unchecked")
public List<CompoundTag> getCompoundList(String key) {
return (List<CompoundTag>) getTagList(key, TagType.COMPOUND);
}
////////////////////////////////////////////////////////////////////////////
// Simple is
public boolean isByte(String key) {
return is(key, ByteTag.class);
}
public boolean isShort(String key) {
return is(key, ShortTag.class);
}
public boolean isInt(String key) {
return is(key, IntTag.class);
}
public boolean isLong(String key) {
return is(key, LongTag.class);
}
public boolean isFloat(String key) {
return is(key, FloatTag.class);
}
public boolean isDouble(String key) {
return is(key, DoubleTag.class);
}
public boolean isByteArray(String key) {
return is(key, ByteArrayTag.class);
}
public boolean isString(String key) {
return is(key, StringTag.class);
}
public boolean isIntArray(String key) {
return is(key, IntArrayTag.class);
}
////////////////////////////////////////////////////////////////////////////
// Fancy is
public boolean isList(String key, TagType type) {
if (!is(key, ListTag.class)) return false;
ListTag tag = getTag(key, ListTag.class);
return tag.getChildType() == type;
}
public boolean isCompound(String key) {
return is(key, CompoundTag.class);
}
////////////////////////////////////////////////////////////////////////////
// Simple sets
public void putBool(String key, boolean value) {
putByte(key, value ? 1 : 0);
}
public void putByte(String key, int value) {
put(key, new ByteTag((byte) value));
}
public void putShort(String key, int value) {
put(key, new ShortTag((short) value));
}
public void putInt(String key, int value) {
put(key, new IntTag(value));
}
public void putLong(String key, long value) {
put(key, new LongTag(value));
}
public void putFloat(String key, double value) {
put(key, new FloatTag((float) value));
}
public void putDouble(String key, double value) {
put(key, new DoubleTag(value));
}
public void putByteArray(String key, byte[] value) {
put(key, new ByteArrayTag(value));
}
public void putString(String key, String value) {
put(key, new StringTag(value));
}
public void putIntArray(String key, int[] value) {
put(key, new IntArrayTag(value));
}
////////////////////////////////////////////////////////////////////////////
// Fancy sets
public <V> void putList(String key, TagType type, List<V> value) {
// the reflection here is really gross but I'm not sure a good way around it
try {
Constructor<? extends Tag> constructor = type.getConstructor();
List<Tag> result = new ArrayList<>(value.size());
for (V item : value) {
result.add(constructor.newInstance(item));
}
put(key, new ListTag<>(type, result));
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException("Unable to create list of type " + type, e);
}
}
public void putCompound(String key, CompoundTag tag) {
put(key, tag);
}
public void putCompoundList(String key, List<CompoundTag> list) {
put(key, new ListTag<>(TagType.COMPOUND, list));
}
////////////////////////////////////////////////////////////////////////////
// Accessor helpers
private <T extends Tag<?>> boolean is(String key, Class<T> clazz) {
if (!containsKey(key)) return false;
final Tag tag = value.get(key);
return tag != null && clazz == tag.getClass();
}
void put(String key, Tag tag) {
Validate.notNull(key, "Key cannot be null");
Validate.notNull(tag, "Tag cannot be null");
value.put(key, tag);
}
private <V, T extends Tag<V>> V get(String key, Class<T> clazz) {
return getTag(key, clazz).getValue();
}
@SuppressWarnings("unchecked")
private <T extends Tag<?>> T getTag(String key, Class<T> clazz) {
if (!is(key, clazz)) {
throw new IllegalArgumentException("Compound does not contain " + clazz.getSimpleName() + " \"" + key + "\"");
}
return (T) value.get(key);
}
private List<? extends Tag> getTagList(String key, TagType type) {
ListTag<?> tag = getTag(key, ListTag.class);
if (tag.getValue().size() == 0) {
// empty lists are allowed to be the wrong type
return Arrays.asList();
}
if (tag.getChildType() != type) {
throw new IllegalArgumentException("List \"" + key + "\" contains " + tag.getChildType() + ", not " + type);
}
return tag.getValue();
}
}