package org.javers.shadow;
import org.javers.core.metamodel.object.CdoSnapshot;
import org.javers.core.metamodel.type.EnumerableType;
import org.javers.core.metamodel.type.JaversProperty;
import java.util.HashSet;
import java.util.Set;
/**
* @author bartosz.walacik
*/
class ShadowBuilder {
private final CdoSnapshot cdoSnapshot;
private Object shadow;
private Set<Wiring> wirings = new HashSet<>();
ShadowBuilder(CdoSnapshot cdoSnapshot, Object shadow) {
this.cdoSnapshot = cdoSnapshot;
this.shadow = shadow;
}
void withStub(Object shadowStub) {
this.shadow = shadowStub;
}
Object getShadow() {
return shadow;
}
/**
* nullable
*/
CdoSnapshot getCdoSnapshot() {
return cdoSnapshot;
}
void addReferenceWiring(JaversProperty property, ShadowBuilder targetShadow) {
this.wirings.add(new ReferenceWiring(property, targetShadow));
}
void addEnumerableWiring(JaversProperty property, Object targetWithShadows) {
this.wirings.add(new EnumerableWiring(property, targetWithShadows));
}
void wire() {
wirings.forEach(Wiring::wire);
}
private abstract class Wiring {
final JaversProperty property;
Wiring(JaversProperty property) {
this.property = property;
}
abstract void wire();
}
private class ReferenceWiring extends Wiring {
final ShadowBuilder target;
ReferenceWiring(JaversProperty property, ShadowBuilder targetShadow) {
super(property);
this.target = targetShadow;
}
@Override
void wire() {
property.set(shadow, target.shadow);
}
}
private class EnumerableWiring extends Wiring {
final Object targetWithShadows;
EnumerableWiring(JaversProperty property, Object targetWithShadows) {
super(property);
this.targetWithShadows = targetWithShadows;
}
@Override
void wire() {
EnumerableType propertyType = property.getType();
Object targetContainer = propertyType.map(targetWithShadows, (valueOrShadow) -> {
if (valueOrShadow instanceof ShadowBuilder) {
//injecting reference to shadow
return ((ShadowBuilder) valueOrShadow).shadow;
}
return valueOrShadow; //vale is passed as is
});
property.set(shadow, targetContainer);
}
}
}