package org.lenskit.results;

import jdk.nashorn.internal.ir.annotations.Immutable;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.lenskit.api.Result;

import java.io.Serializable;

/**
 * A basic {@link Result} implementation with no details.
 *
 * @see Results
 */
@Immutable
public class BasicResult implements Result, Serializable {
    private static final long serialVersionUID = 1L;

    protected final long id;
    protected final double score;

    public BasicResult(long id, double score) {
        this.id = id;
        this.score = score;
    }

    @Override
    public long getId() {
        return id;
    }

    @Override
    public double getScore() {
        return score;
    }

    @Override
    public boolean hasScore() {
        return !Double.isNaN(score);
    }

    /**
     * Compare this result with another for equality.  Instance of this result type are only equal with other basic
     * result instances; to compare general results for equality, first convert them to basic results with
     * {@link Results#basicCopy(Result)}.  Detailed results that extend this class **must** override both this method
     * and {@link #hashCode()}.
     *
     * @param o The object to compare with.
     * @return `true` if the objects are equivalent.
     */
    @Override
    public boolean equals(Object o) {
        assert getClass().equals(BasicResult.class): "subclass failed to override equals()";
        if (o == this) {
            return true;
        } else if (o != null && o.getClass().equals(BasicResult.class)) {
            BasicResult or = (BasicResult) o;
            return new EqualsBuilder().append(id, or.id)
                                      .append(score, or.score)
                                      .isEquals();
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        assert getClass().equals(BasicResult.class): "subclass failed to override hashCode()";
        return new HashCodeBuilder().append(id).append(score).toHashCode();
    }
}

@@ -1247,16 +1247,171 @@
 %0A     *%0A
+     * Subclasses should **not** call this method; they can use %7B@link #startEquality(Result)%7D to reuse the logic for%0A     * checking ID and score.%0A     *%0A
      * @
@@ -1845,108 +1845,80 @@
 urn 
-new EqualsBuilder().append(id, or.id)%0A                                      .append(score, or.score)
+startEquality(or).isEquals();%0A        %7D else %7B%0A            return false;
 %0A   
@@ -1926,110 +1926,205 @@
     
+%7D%0A
     
+%7D%0A%0A
     
-    
+/**%0A
      
- 
+* %7B@inheritDoc%7D%0A
      
+*%0A
      
-  .isEquals();%0A        %7D else %7B%0A            return false;%0A        %7D%0A    %7D%0A
+* Subclasses should **not** call this method; they can use %7B@link #startHashCode()%7D to reuse the logic for%0A     * hashing the ID and score.%0A     */
 %0A   
@@ -2276,66 +2276,892 @@
 urn 
-new HashCodeBuilder().append(id).append(score).toHashCode(
+startHashCode().toHashCode();%0A    %7D%0A%0A    /**%0A     * Create a hash code builder, populated with the ID and score.  Subclasses can use this as a starting point for%0A     * building a hash code.%0A     *%0A     * @return A hash code builder that has the ID and score already appended.%0A     */%0A    protected HashCodeBuilder startHashCode() %7B%0A        return new HashCodeBuilder().append(id).append(score);%0A    %7D%0A%0A    /**%0A     * Create an equality builder, populated with the ID and score.  Subclasses can use this as a starting point for%0A     * checking equality.%0A     *%0A     * @param r The other result.%0A     * @return An equality builder, that has the ID and score of this result and %60r%60 already appended to it.%0A     */%0A    protected EqualsBuilder startEquality(Result r) %7B%0A        return new EqualsBuilder().append(id, r.getId())%0A                                  .append(score, r.getScore()
 );%0A 

Support subclassing BasicResult