package mhfc.net.common.quests.properties;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Function;
import com.google.common.base.Preconditions;
import mhfc.net.common.util.Lazy;
import mhfc.net.common.util.parsing.Context;
import mhfc.net.common.util.parsing.Holder;
import mhfc.net.common.util.parsing.IValueHolder;
import mhfc.net.common.util.parsing.proxies.MapProxy;
import mhfc.net.common.util.parsing.proxies.MemberMethodProxy;
import mhfc.net.common.util.reflection.MethodHelper;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
public class GroupProperty extends Property {
private Map<String, Property> subProperties = new HashMap<>();
private Map<String, IValueHolder> supplementVisuals = new HashMap<>();
private Lazy<Holder> propertyProxy;
private GroupProperty(Runnable setDirtyParent) {
super(setDirtyParent);
propertyProxy = new Lazy<>(() -> Holder.valueOf(new MapProxy(subProperties, supplementVisuals)));
}
@Override
public NBTTagCompound dumpUpdates() {
if (!pollDirty()) {
return signalNoUpdates();
}
NBTTagCompound updateTag = new NBTTagCompound();
for (Entry<String, Property> mapping : subProperties.entrySet()) {
NBTBase elementUpdate = mapping.getValue().dumpUpdates();
if (signalsNoUpdates(elementUpdate)) {
continue;
}
String name = mapping.getKey();
updateTag.setTag(name, elementUpdate);
}
return updateTag;
}
@Override
public NBTTagCompound dumpAll() {
NBTTagCompound updateTag = new NBTTagCompound();
for (Entry<String, Property> mapping : subProperties.entrySet()) {
NBTBase elementUpdate = mapping.getValue().dumpAll();
String name = mapping.getKey();
updateTag.setTag(name, elementUpdate);
}
return updateTag;
}
@Override
public void updateFrom(NBTBase nbt) {
NBTTagCompound tag = NBTType.TAG_COMPOUND.assureTagType(nbt);
for (Entry<String, Property> mapping : subProperties.entrySet()) {
String name = mapping.getKey();
if (!tag.hasKey(name)) {
continue;
}
mapping.getValue().updateFrom(tag.getTag(name));
}
}
@Override
public Holder snapshot() throws Throwable {
return propertyProxy.get();
}
/**
* Registers a new member in the property group. The second parameter is usually by a static method call to the type
* of property. E.g:
*
* <pre>
* <code>
* group.newMember("endTime", IntProperty.construct(3));
* </code>
* </pre>
*
* @param name
* the name of th property. must be unique in this group and conform to the specs of {@link Context}.
* @param constructor
* @return the property to be used.
*/
public <P extends Property> P newMember(String name, Function<Runnable, P> constructor) {
name = Context.checkKeySyntax(name);
Preconditions.checkArgument(!subProperties.containsKey(name), "Member name " + name + " already taken");
P prop = Objects.requireNonNull(constructor.apply(getDirtyPropagator()));
subProperties.put(name, prop);
return prop;
}
/**
* Registers a visual-only entry in the group-properties. This is important to be able to introduce display
* functions and/or constants into the parsing context.<br>
* As they are visual-only, it will not be checked whether a name already exists, or if a member of the same name
* exists. When a member of the same name exists, the context refers to the member rather than the value holder.<br>
*
* @param notShared
* a value holder that will not be synced between client and server
* @see MemberMethodProxy to register functions as variables
*/
public void newVisualSupplement(String name, IValueHolder notShared) {
Objects.requireNonNull(name);
Objects.requireNonNull(notShared);
supplementVisuals.put(name, notShared);
}
/**
* Searches clazz for a static method "methodName" and introduces the method into the context under the name of
* "alias". It is an error if that method is not public or can not be found.
*
* @param alias
* @param clazz
* @param methodName
*/
public void newVisualSupplementMethod(String alias, Class<?> clazz, String methodName) {
newVisualSupplement(
alias,
Holder.valueOf(new MemberMethodProxy(MethodHelper.findStatic(clazz, methodName).get())));
}
/**
* Can be used in {@link GroupProperty#newMember(String, Function)}
*
* @param initialValue
* the initial value of the property
* @return
*/
public static Function<Runnable, GroupProperty> construct() {
return GroupProperty::new;
}
public static GroupProperty makeRootProperty() {
return new GroupProperty(null);
}
@Override
public String toString() {
return this.subProperties.toString();
}
}