001package de.monochromata.anaphors.ast;
002
003import static java.util.Optional.empty;
004
005import java.util.Optional;
006import java.util.function.Supplier;
007
008import de.monochromata.anaphors.ast.relatedexp.RelatedExpression;
009
010/**
011 * A default implementation of an indirect anaphora relation.
012 *
013 * @param <N>  The node type in the AST
014 * @param <E>  The expression type
015 * @param <T>  The type type
016 * @param <B>  The binding type
017 * @param <TB> The type binding type
018 * @param <S>  The scope type (optional)
019 * @param <I>  The type used to represent identifiers
020 * @param <QI> The type used to represent qualified identifiers
021 * @param <R>  The sub-type of related expression to use
022 * @param <A>  The sub-type of AST-based anaphora to use
023 */
024public class DefaultIndirectAnaphora<N, E, T, B, TB extends B, S, I, QI, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>>
025        extends AbstractASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>
026        implements IndirectAnaphora<N, E, T, B, TB, S, I, QI, R, A> {
027
028    private final String underspecifiedRelation;
029    private final Optional<Supplier<String>> customReferenceDescriptionSupplier;
030
031    /**
032     * Used in contract testing.
033     */
034    @SuppressWarnings("unused")
035    protected DefaultIndirectAnaphora() {
036        underspecifiedRelation = null;
037        customReferenceDescriptionSupplier = null;
038    }
039
040    public DefaultIndirectAnaphora(final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpressionPart,
041            final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphorPart, final String underspecifiedRelation,
042            final boolean isUnderspecified) {
043        this(relatedExpressionPart, anaphorPart, underspecifiedRelation, empty(), isUnderspecified);
044    }
045
046    public DefaultIndirectAnaphora(final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpressionPart,
047            final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphorPart, final String underspecifiedRelation,
048            final Supplier<String> customReferenceDescriptionSupplier, final boolean isUnderspecified) {
049        this(relatedExpressionPart, anaphorPart, underspecifiedRelation,
050                Optional.of(customReferenceDescriptionSupplier), isUnderspecified);
051    }
052
053    protected DefaultIndirectAnaphora(final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpressionPart,
054            final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphorPart, final String underspecifiedRelation,
055            final Optional<Supplier<String>> customReferenceDescriptionSupplier, final boolean isUnderspecified) {
056        super(relatedExpressionPart, anaphorPart, isUnderspecified);
057        this.underspecifiedRelation = underspecifiedRelation;
058        this.customReferenceDescriptionSupplier = customReferenceDescriptionSupplier;
059    }
060
061    /*
062     * (non-Javadoc)
063     *
064     * @see de.monochromata.anaphors.IndirectAnaphora#getUnderspecifiedRelation()
065     */
066    @Override
067    public String getUnderspecifiedRelation() {
068        return underspecifiedRelation;
069    }
070
071    @Override
072    public String getReferenceDescription() {
073        return customReferenceDescriptionSupplier.map(Supplier::get).orElseGet(this::getDefaultReferenceDescription);
074    }
075
076    protected String getDefaultReferenceDescription() {
077        return getReferent().getDescription() + " of " + getRelatedExpression().getRelatedExpression() + " at "
078                + getRelatedExpression().getLine() + ":" + getRelatedExpression().getColumn() + " (" + getKind() + ")";
079    }
080
081    @Override
082    public int hashCode() {
083        final int prime = 31;
084        int result = super.hashCode();
085        result = prime * result + ((underspecifiedRelation == null) ? 0 : underspecifiedRelation.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 DefaultIndirectAnaphora other = (DefaultIndirectAnaphora) obj;
101        if (underspecifiedRelation == null) {
102            if (other.underspecifiedRelation != null) {
103                return false;
104            }
105        } else if (!underspecifiedRelation.equals(other.underspecifiedRelation)) {
106            return false;
107        }
108        return true;
109    }
110
111    @Override
112    public String toString() {
113        return getKind() + " [getUnderspecifiedRelation()=" + underspecifiedRelation + ", getRelatedExpression()="
114                + getRelatedExpression() + ", getAnaphor()=" + getAnaphor() + ", getAnaphorExpression()="
115                + getAnaphorExpression() + ", getReferent()=" + getReferent() + ", getRelatedExpressionStrategy()="
116                + getRelatedExpressionStrategy() + ", getAnaphorResolutionStrategy()=" + getAnaphorResolutionStrategy()
117                + ", getReferentializationStrategy()=" + getReferentializationStrategy() + ", getBinding()="
118                + getBinding() + ", isUnderspecified()=" + isUnderspecified() + ", isExplicated()=" + isExplicated()
119                + "]";
120    }
121
122}