package de.take_weiland.mods.commons.internal.sync;
import com.google.common.base.Function;
import de.take_weiland.mods.commons.internal.TypeToFactoryMap;
import de.take_weiland.mods.commons.internal.prop.AbstractProperty;
import de.take_weiland.mods.commons.serialize.Property;
import de.take_weiland.mods.commons.sync.Sync;
import de.take_weiland.mods.commons.sync.Syncer;
import de.take_weiland.mods.commons.sync.SyncerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle;
import java.util.Map;
import static com.google.common.base.Preconditions.checkState;
import static java.lang.invoke.MethodType.methodType;
/**
* <p>Factory for @SyncCompanions.</p>
* @author diesieben07
*/
public final class SyncCompanions {
private static final CompanionFactory companionFactory = new DefaultCompanionFactory();
private static final ClassValue<MethodHandle> companionConstructors = new ClassValue<MethodHandle>() {
@Override
protected synchronized MethodHandle computeValue(@Nonnull Class<?> type) {
MethodHandle cstr = companionFactory.getCompanionConstructor(type);
checkState(cstr.type().equals(methodType(SyncCompanion.class)));
return cstr;
}
};
private static final TypeToFactoryMap<SyncerFactory, Syncer<?, ?>> syncerFactories = new TypeToFactoryMap<SyncerFactory, Syncer<?, ?>>() {
@Override
protected Syncer<?, ?> applyFactory(SyncerFactory factory, Property<?, ?> type) {
return factory.getSyncer(type);
}
};
/**
* <p>Register a new SyncerFactory.</p>
* @param clazz the base class
* @param factory the factory
*/
public static void registerSyncerFactory(Class<?> clazz, SyncerFactory factory) {
syncerFactories.register(clazz, factory);
}
/**
* <p>Create a new SyncCompanion for the given class.</p>
* @param clazz the class
* @return a SyncCompanion
*/
public static SyncCompanion newCompanion(Class<?> clazz) throws Throwable {
return (SyncCompanion) companionConstructors.get(clazz).invokeExact();
}
static Map<Property<?, ?>, Syncer<?, ?>> getSyncedMemberInfo(Class<?> clazz) {
return AbstractProperty.allPropertiesLazy(clazz, Sync.class)
.toMap(getSyncer());
}
private static Function<Property<?, ?>, Syncer<?, ?>> getSyncer() {
return new Function<Property<?, ?>, Syncer<?, ?>>() {
@Nullable
@Override
public Syncer<?, ?> apply(@Nullable Property<?, ?> property) {
return syncerFactories.get(property);
}
};
}
private SyncCompanions() { }
}