package shcm.shsupercm.fabric.citresewn.pack.format;
import net.minecraft.util.Identifier;
import net.minecraft.util.InvalidIdentifierException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
* Storage agnostic map of keys and values.
* Keys are stored as {@link PropertyKey}s holding the mod id of the property type.
* A key can have multiple values associated with it as they are stored in an ordered set.
*
* @see PropertyKey
* @see PropertyValue
* @see PropertiesGroupAdapter
*/
public abstract class PropertyGroup {
/**
* The internal map that backs this property group.
*/
public final Map> properties = new LinkedHashMap<>();
/**
* This group's location in its resourcepack.
*/
public final Identifier identifier;
/**
* The file name of the resourcepack that this property group is in.
*/
public final String packName;
protected PropertyGroup(String packName, Identifier identifier) {
this.packName = packName;
this.identifier = identifier;
}
/**
* Tries to parse a group out of a stream.
* @see #load(String, Identifier, InputStream)
* @see #getExtension()
* @see PropertiesGroupAdapter
* @param packName {@link #packName}
* @param identifier {@link #identifier}, needed for extension matching
* @param is a stream containing properties as specified by implementation
* @return the parsed group or null if could not match an adapter
* @throws IOException if errored while parsing the group
*/
public static PropertyGroup tryParseGroup(String packName, Identifier identifier, InputStream is) throws IOException {
PropertyGroup group = null;
if (identifier.getPath().endsWith(PropertiesGroupAdapter.EXTENSION))
group = new PropertiesGroupAdapter(packName, identifier);
return group == null ? null : group.load(packName, identifier, is);
}
/**
* @return file suffix for this property group's implementation
*/
public abstract String getExtension();
/**
* Reads the given input stream into the group.
* @param packName {@link #packName}
* @param identifier {@link #identifier}
* @param is a stream containing properties as specified by implementation
* @return this
* @throws IOException if errored while reading the stream
* @throws InvalidIdentifierException if encountered a malformed {@link Identifier} while reading
*/
public abstract PropertyGroup load(String packName, Identifier identifier, InputStream is) throws IOException, InvalidIdentifierException;
/**
* Adds the given value to the group.
* @param position implementation specific interpretation of the value's position in the group, has no effect on internal order
* @param packName the value's resourcepack file name
* @param propertiesIdentifier the value's property group location identifier
* @param key the value's key name
* @param keyMetadata nullable, implementation specific metadata for this value's key
* @param separator implementation specific connection between the key and the value
* @param value string representation of the value to be parsed by the group's user
*/
protected void put(int position, String packName, Identifier propertiesIdentifier, String key, String keyMetadata, PropertySeparator separator, String value) {
Objects.requireNonNull(key);
Objects.requireNonNull(value);
this.properties.computeIfAbsent(PropertyKey.of(key), id -> new LinkedHashSet<>()).add(new PropertyValue(keyMetadata, value, separator, position, propertiesIdentifier, packName));
}
/**
* @param namespace the key's namespace(should be the value type's modid by convention)
* @param pathAliases all key name aliases to check for
* @return all values associated with the given key by alias>insertion order
*/
public Set get(String namespace, String... pathAliases) {
Set values = new LinkedHashSet<>();
for (String path : pathAliases) {
Set possibleValues = this.properties.get(new PropertyKey(namespace, path));
if (possibleValues != null)
values.addAll(possibleValues);
}
return values;
}
/**
* @see #getLastWithoutMetadataOrDefault(String, String, String...)
* @param namespace the key's namespace(should be the value type's modid by convention)
* @param pathAliases all key name aliases to check for
* @return the last value associated with the key(by insertion order) that has a null key metadata or null if the key is not present in the group
*/
public PropertyValue getLastWithoutMetadata(String namespace, String... pathAliases) {
PropertyValue value = null;
for (PropertyValue next : get(namespace, pathAliases))
if (next.keyMetadata() == null)
value = next;
return value;
}
/**
* @see #getLastWithoutMetadata(String, String...)
* @param defaultValue the dummy value to return if not present in the group
* @param namespace the key's namespace(should be the value type's modid by convention)
* @param pathAliases all key name aliases to check for
* @return the last value associated with the key(by insertion order) that has a null key metadata or the wrapped default value if the key is not present in the group
*/
public PropertyValue getLastWithoutMetadataOrDefault(String defaultValue, String namespace, String... pathAliases) {
PropertyValue property = getLastWithoutMetadata(namespace, pathAliases);
if (property == null)
property = new PropertyValue(null, defaultValue, PropertySeparator.EQUALS, -1, this.identifier, this.packName);
return property;
}
/**
* @see #getExtension()
* @see #identifier
* @return the name of this group without its path or extension
*/
public String stripName() {
return identifier.getPath().substring(identifier.getPath().lastIndexOf('/') + 1, identifier.getPath().length() - getExtension().length());
}
/**
* Compiles a message with attached info on a value's origin.
* @param message message to add descriptor to
* @param position implementation specific position of
* @return the formatted message
*/
public String messageWithDescriptorOf(String message, int position) {
return message + (position != -1 ? " @L" + position : "") + " in " + this.identifier.toString() + " from " + this.packName;
}
}