001package de.monochromata.anaphors.ast.reference.strategy.feature;
002
003import de.monochromata.anaphors.ast.feature.FeatureContainer;
004import de.monochromata.anaphors.ast.reference.Referent;
005import de.monochromata.anaphors.ast.reference.strategy.AbstractReferentializationStrategy;
006import de.monochromata.anaphors.ast.reference.strategy.concept.ConceptReferentializationStrategy;
007import de.monochromata.anaphors.ast.spi.AnaphorsSpi;
008
009/**
010 * Referentialization based on feature recurrence (i.e. matching referents whose
011 * type is equal to a suffix of the simple name that acts as definite expression
012 * and that declare a feature in the constructor invocation that recurs in the
013 * non-empty prefix to the suffix of the simple name).
014 *
015 * <p>
016 * Note
017 * </p>
018 *
019 * TODO: Ensure non-empty prefix to the type name in the simple name
020 *
021 * TODO: Make sure all features from the simple name are found in the referent
022 *
023 * TODO: Collect features not only from the constructor, but also from other
024 * downstream accesses
025 *
026 * TODO: Implement matching of multiple features and flexible length of type
027 * names ...
028 *
029 * @param <N>  The node type in the AST
030 * @param <E>  The expression type
031 * @param <CI> The class instance creation expression node type
032 * @param <B>  The binding type
033 * @param <TB> The type binding type
034 * @param <S>  The scope type (optional)
035 * @param <I>  The type used to represent identifiers
036 * @param <QI> The type used to represent qualified identifiers
037 * @param <EV> The type of the event contained in the condition that is
038 *             evaluated to check when the perspectivations shall be applied.
039 * @param <PP> The type used for positions that carry perspectivations
040 */
041public class FeatureRecurrence<N, E, CI extends N, B, TB extends B, S, I, QI, EV, PP>
042        extends AbstractReferentializationStrategy<N, E, TB, S, I, QI, EV, PP>
043        implements FeatureReferentializationStrategy<E, TB, S, I, QI> {
044
045    public static final String Rf_KIND_PREFIX = "Rf";
046    private final ConceptReferentializationStrategy<E, TB, S, I, QI> delegate;
047
048    /**
049     * Used in contract testing.
050     */
051    @SuppressWarnings("unused")
052    protected FeatureRecurrence() {
053        delegate = null;
054    }
055
056    public FeatureRecurrence(final ConceptReferentializationStrategy<E, TB, S, I, QI> delegate,
057            final AnaphorsSpi<N, E, TB, S, I, QI, EV, PP> anaphorsSpi) {
058        super(anaphorsSpi);
059        this.delegate = delegate;
060    }
061
062    @Override
063    public boolean canReferTo(final I idFromDefiniteExpression, final Referent<TB, S, I, QI> potentialReferent,
064            final S scope) {
065        final FeatureContainer<QI> featuresInIdentifier = delegate
066                .getFeaturesRemainingInIdentifierIfItCanReferUsingConceptualType(idFromDefiniteExpression,
067                        potentialReferent, scope);
068        return featuresInIdentifier != null && potentialReferent.containsFeaturesOf(featuresInIdentifier);
069    }
070
071    @Override
072    public ConceptReferentializationStrategy<E, TB, S, I, QI> getDelegate() {
073        return delegate;
074    }
075
076    @Override
077    public String getKind() {
078        return Rf_KIND_PREFIX + delegate.getKind();
079    }
080
081    @Override
082    public int hashCode() {
083        final int prime = 31;
084        int result = super.hashCode();
085        result = prime * result + ((delegate == null) ? 0 : delegate.hashCode());
086        return result;
087    }
088
089    @Override
090    public boolean equals(final Object obj) {
091        if (this == obj) {
092            return true;
093        }
094        if (!super.equals(obj)) {
095            return false;
096        }
097        if (getClass() != obj.getClass()) {
098            return false;
099        }
100        final FeatureRecurrence other = (FeatureRecurrence) obj;
101        if (delegate == null) {
102            if (other.delegate != null) {
103                return false;
104            }
105        } else if (!delegate.equals(other.delegate)) {
106            return false;
107        }
108        return true;
109    }
110
111}