package org.optaplanner.core.impl.domain.variable.listener.support.violation;

import java.util.Objects;
import java.util.function.Consumer;

import org.optaplanner.core.api.domain.variable.VariableListener;
import org.optaplanner.core.impl.domain.variable.descriptor.ShadowVariableDescriptor;

final class ShadowVariableSnapshot {

    private final ShadowVariableDescriptor<?> shadowVariableDescriptor;
    private final Object entity;
    private final Object originalValue;

    private ShadowVariableSnapshot(ShadowVariableDescriptor<?> shadowVariableDescriptor, Object entity, Object originalValue) {
        this.shadowVariableDescriptor = shadowVariableDescriptor;
        this.entity = entity;
        this.originalValue = originalValue;
    }

    static ShadowVariableSnapshot of(ShadowVariableDescriptor<?> shadowVariableDescriptor, Object entity) {
        return new ShadowVariableSnapshot(shadowVariableDescriptor, entity, shadowVariableDescriptor.getValue(entity));
    }

    void validate(Consumer<String> violationMessageConsumer) {
        Object newValue = shadowVariableDescriptor.getValue(entity);
        if (!Objects.equals(originalValue, newValue)) {
            violationMessageConsumer.accept("    The entity (" + entity
                    + ")'s shadow variable (" + shadowVariableDescriptor.getSimpleEntityAndVariableName()
                    + ")'s corrupted value (" + originalValue + ") changed to uncorrupted value (" + newValue
                    + ") after all " + VariableListener.class.getSimpleName()
                    + "s were triggered without changes to the genuine variables.\n"
                    + "      Maybe the " + VariableListener.class.getSimpleName() + " class ("
                    + shadowVariableDescriptor.getVariableListenerClass().getSimpleName()
                    + ") for that shadow variable (" + shadowVariableDescriptor.getSimpleEntityAndVariableName()
                    + ") forgot to update it when one of its sources changed.\n");
        }
    }

    ShadowVariableDescriptor<?> getShadowVariableDescriptor() {
        return shadowVariableDescriptor;
    }
}

@@ -2129,11 +2129,161 @@
 r;%0A    %7D
+%0A%0A    @Override%0A    public String toString() %7B%0A        return entity + %22.%22 + shadowVariableDescriptor.getVariableName() + %22 = %22 + originalValue;%0A    %7D
 %0A%7D%0A

Add snapshot toString() to improve debugging experience