Index: src/java/org/apache/lucene/search/BooleanQuery.java
===================================================================
--- src/java/org/apache/lucene/search/BooleanQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/BooleanQuery.java	(working copy)
@@ -224,7 +224,7 @@
       }
     }
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc)
+    public Explanation explain(IndexReader reader, int doc)
       throws IOException {
       final int minShouldMatch =
         BooleanQuery.this.getMinimumNumberShouldMatch();
@@ -241,7 +241,7 @@
         if (w.scorer(reader, true, true) == null) {
           continue;
         }
-        Explanation e = w.explain(searcher, reader, doc);
+        Explanation e = w.explain(reader, doc);
         if (!c.isProhibited()) maxCoord++;
         if (e.isMatch()) {
           if (!c.isProhibited()) {
Index: src/java/org/apache/lucene/search/ConstantScoreQuery.java
===================================================================
--- src/java/org/apache/lucene/search/ConstantScoreQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/ConstantScoreQuery.java	(working copy)
@@ -81,7 +81,7 @@
       return new ConstantScorer(similarity, reader, this);
     }
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc) throws IOException {
+    public Explanation explain(IndexReader reader, int doc) throws IOException {
       
       ConstantScorer cs = new ConstantScorer(similarity, reader, this);
       boolean exists = cs.docIdSetIterator.advance(doc) == doc;
Index: src/java/org/apache/lucene/search/DisjunctionMaxQuery.java
===================================================================
--- src/java/org/apache/lucene/search/DisjunctionMaxQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/DisjunctionMaxQuery.java	(working copy)
@@ -152,13 +152,13 @@
     }
 
     /* Explain the score we computed for doc */
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc) throws IOException {
-      if (disjuncts.size() == 1) return ((Weight) weights.get(0)).explain(searcher, reader,doc);
+    public Explanation explain(IndexReader reader, int doc) throws IOException {
+      if (disjuncts.size() == 1) return ((Weight) weights.get(0)).explain(reader,doc);
       ComplexExplanation result = new ComplexExplanation();
       float max = 0.0f, sum = 0.0f;
       result.setDescription(tieBreakerMultiplier == 0.0f ? "max of:" : "max plus " + tieBreakerMultiplier + " times others of:");
       for (Iterator iter = weights.iterator(); iter.hasNext();) {
-        Explanation e = ((Weight) iter.next()).explain(searcher, reader, doc);
+        Explanation e = ((Weight) iter.next()).explain(reader, doc);
         if (e.isMatch()) {
           result.setMatch(Boolean.TRUE);
           result.addDetail(e);
Index: src/java/org/apache/lucene/search/FilteredQuery.java
===================================================================
--- src/java/org/apache/lucene/search/FilteredQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/FilteredQuery.java	(working copy)
@@ -73,8 +73,8 @@
         weight.normalize(v);
         value = weight.getValue() * getBoost();
       }
-      public Explanation explain (Searcher searcher, IndexReader ir, int i) throws IOException {
-        Explanation inner = weight.explain (searcher, ir, i);
+      public Explanation explain (IndexReader ir, int i) throws IOException {
+        Explanation inner = weight.explain (ir, i);
         if (getBoost()!=1) {
           Explanation preBoost = inner;
           inner = new Explanation(inner.getValue()*getBoost(),"product of:");
Index: src/java/org/apache/lucene/search/IndexSearcher.java
===================================================================
--- src/java/org/apache/lucene/search/IndexSearcher.java	(revision 806928)
+++ src/java/org/apache/lucene/search/IndexSearcher.java	(working copy)
@@ -313,7 +313,7 @@
     int n = ReaderUtil.subIndex(doc, docStarts);
     int deBasedDoc = doc - docStarts[n];
     
-    return weight.explain(this, subReaders[n], deBasedDoc);
+    return weight.explain(subReaders[n], deBasedDoc);
   }
 
   private boolean fieldSortDoTrackScores;
Index: src/java/org/apache/lucene/search/MatchAllDocsQuery.java
===================================================================
--- src/java/org/apache/lucene/search/MatchAllDocsQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/MatchAllDocsQuery.java	(working copy)
@@ -129,7 +129,7 @@
           normsField != null ? reader.norms(normsField) : null);
     }
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc) {
+    public Explanation explain(IndexReader reader, int doc) {
       // explain query weight
       Explanation queryExpl = new ComplexExplanation
         (true, getValue(), "MatchAllDocsQuery, product of:");
Index: src/java/org/apache/lucene/search/MultiPhraseQuery.java
===================================================================
--- src/java/org/apache/lucene/search/MultiPhraseQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/MultiPhraseQuery.java	(working copy)
@@ -186,7 +186,7 @@
                                       slop, reader.norms(field));
     }
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc)
+    public Explanation explain(IndexReader reader, int doc)
       throws IOException {
       ComplexExplanation result = new ComplexExplanation();
       result.setDescription("weight("+getQuery()+" in "+doc+"), product of:");
Index: src/java/org/apache/lucene/search/PhraseQuery.java
===================================================================
--- src/java/org/apache/lucene/search/PhraseQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/PhraseQuery.java	(working copy)
@@ -24,6 +24,7 @@
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermPositions;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Similarity.SimExplain;
 import org.apache.lucene.util.ToStringUtils;
 
 /** A Query that matches documents containing a particular sequence of terms.
@@ -112,12 +113,14 @@
     private float idf;
     private float queryNorm;
     private float queryWeight;
+    private String termExp;
 
     public PhraseWeight(Searcher searcher)
       throws IOException {
       this.similarity = getSimilarity(searcher);
-
-      idf = similarity.idf(terms, searcher);
+      SimExplain simExp = similarity.idfExplain(terms, searcher);
+      termExp = simExp.explain();
+      idf = simExp.getIdf();
     }
 
     public String toString() { return "weight(" + PhraseQuery.this + ")"; }
@@ -158,7 +161,7 @@
 
     }
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc)
+    public Explanation explain(IndexReader reader, int doc)
       throws IOException {
 
       Explanation result = new Explanation();
@@ -167,24 +170,20 @@
       StringBuffer docFreqs = new StringBuffer();
       StringBuffer query = new StringBuffer();
       query.append('\"');
+      docFreqs.append(termExp);
       for (int i = 0; i < terms.size(); i++) {
         if (i != 0) {
-          docFreqs.append(" ");
           query.append(" ");
         }
 
         Term term = (Term)terms.get(i);
 
-        docFreqs.append(term.text());
-        docFreqs.append("=");
-        docFreqs.append(reader.docFreq(term));
-
         query.append(term.text());
       }
       query.append('\"');
 
       Explanation idfExpl =
-        new Explanation(idf, "idf(" + field + ": " + docFreqs + ")");
+        new Explanation(idf, "idf(" + field + ":" + docFreqs + ")");
 
       // explain query weight
       Explanation queryExpl = new Explanation();
Index: src/java/org/apache/lucene/search/Similarity.java
===================================================================
--- src/java/org/apache/lucene/search/Similarity.java	(revision 806928)
+++ src/java/org/apache/lucene/search/Similarity.java	(working copy)
@@ -482,6 +482,27 @@
   public float idf(Term term, Searcher searcher) throws IOException {
     return idf(searcher.docFreq(term), searcher.maxDoc());
   }
+  
+  public SimExplain idfExplain(Term term, Searcher searcher) throws IOException {
+    final int df = searcher.docFreq(term);
+    final int max = searcher.maxDoc();
+
+    return new SimExplain() {
+        //@Override
+        public String explain() {
+          return "idf(docFreq=" + df +
+          ", maxDocs=" + max + ")";
+        }
+        //@Override
+        public float getIdf() {
+          return idf(df, max);
+        }};
+  }
+  
+  public static abstract class SimExplain {
+    abstract float getIdf();
+    abstract String explain();
+  }
 
   /** Computes a score factor for a phrase.
    *
@@ -500,6 +521,33 @@
     }
     return idf;
   }
+  
+  public SimExplain idfExplain(Collection terms, Searcher searcher) throws IOException {
+
+    final int max = searcher.maxDoc();
+    float idf = 0.0f;
+    final StringBuffer exp = new StringBuffer();
+    Iterator i = terms.iterator();
+    while (i.hasNext()) {
+      Term term = (Term)i.next();
+      final int df = searcher.docFreq(term);
+      idf += idf(df, max);
+      exp.append(" " + term.text() + "=" + df);
+    }
+    final float fIdf = idf;
+    return new SimExplain() {
+      
+      //@Override
+      float getIdf() {
+        return fIdf;
+      }
+      
+      //@Override
+      String explain() {
+        return exp.toString();
+      }
+    };
+  }
 
   /** Computes a score factor based on a term's document frequency (the number
    * of documents which contain the term).  This value is multiplied by the
Index: src/java/org/apache/lucene/search/TermQuery.java
===================================================================
--- src/java/org/apache/lucene/search/TermQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/TermQuery.java	(working copy)
@@ -18,11 +18,13 @@
  */
 
 import java.io.IOException;
+import java.rmi.UnexpectedException;
 import java.util.Set;
 
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermDocs;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Similarity.SimExplain;
 import org.apache.lucene.util.ToStringUtils;
 
 /** A Query that matches documents containing a term.
@@ -37,11 +39,14 @@
     private float idf;
     private float queryNorm;
     private float queryWeight;
+    private String tfIdfExp;
 
     public TermWeight(Searcher searcher)
       throws IOException {
       this.similarity = getSimilarity(searcher);
-      idf = similarity.idf(term, searcher); // compute idf
+      SimExplain idfSim = similarity.idfExplain(term, searcher);
+      tfIdfExp = idfSim.explain();
+      idf = idfSim.getIdf();
     }
 
     public String toString() { return "weight(" + TermQuery.this + ")"; }
@@ -69,19 +74,13 @@
       return new TermScorer(this, termDocs, similarity, reader.norms(term.field()));
     }
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc)
+    public Explanation explain(IndexReader reader, int doc)
       throws IOException {
 
       ComplexExplanation result = new ComplexExplanation();
       result.setDescription("weight("+getQuery()+" in "+doc+"), product of:");
 
-      Explanation expl;
-      if(searcher == null) {
-        expl = new Explanation(idf, "idf(" + idf + ")");
-      } else {
-        expl = new Explanation(idf, "idf(docFreq=" + searcher.docFreq(term) +
-            ", maxDocs=" + searcher.maxDoc() + ")");
-      }
+      Explanation expl = new Explanation(idf, tfIdfExp);
 
       // explain query weight
       Explanation queryExpl = new Explanation();
Index: src/java/org/apache/lucene/search/Weight.java
===================================================================
--- src/java/org/apache/lucene/search/Weight.java	(revision 806928)
+++ src/java/org/apache/lucene/search/Weight.java	(working copy)
@@ -61,7 +61,7 @@
    * @return an Explanation for the score
    * @throws IOException
    */
-  public abstract Explanation explain(Searcher searcher, IndexReader reader, int doc) throws IOException;
+  public abstract Explanation explain(IndexReader reader, int doc) throws IOException;
 
   /** The query that this concerns. */
   public abstract Query getQuery();
Index: src/java/org/apache/lucene/search/function/CustomScoreQuery.java
===================================================================
--- src/java/org/apache/lucene/search/function/CustomScoreQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/function/CustomScoreQuery.java	(working copy)
@@ -341,17 +341,17 @@
       return new CustomScorer(similarity, reader, this, subQueryScorer, valSrcScorers);
     }
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc) throws IOException {
-      Explanation explain = doExplain(searcher, reader, doc);
-      return explain == null ? new Explanation(0.0f, "no matching docs") : doExplain(searcher, reader, doc);
+    public Explanation explain(IndexReader reader, int doc) throws IOException {
+      Explanation explain = doExplain(reader, doc);
+      return explain == null ? new Explanation(0.0f, "no matching docs") : doExplain(reader, doc);
     }
     
-    private Explanation doExplain(Searcher searcher, IndexReader reader, int doc) throws IOException {
+    private Explanation doExplain(IndexReader reader, int doc) throws IOException {
       Scorer[] valSrcScorers = new Scorer[valSrcWeights.length];
       for(int i = 0; i < valSrcScorers.length; i++) {
          valSrcScorers[i] = valSrcWeights[i].scorer(reader, true, false);
       }
-      Explanation subQueryExpl = subQueryWeight.explain(searcher, reader, doc);
+      Explanation subQueryExpl = subQueryWeight.explain(reader, doc);
       if (!subQueryExpl.isMatch()) {
         return subQueryExpl;
       }
@@ -451,7 +451,7 @@
     // TODO: remove in 3.0
     /*(non-Javadoc) @see org.apache.lucene.search.Scorer#explain(int) */
     public Explanation explain(int doc) throws IOException {
-      Explanation subQueryExpl = weight.subQueryWeight.explain(null, reader,doc); // nocommit: needs resolution
+      Explanation subQueryExpl = weight.subQueryWeight.explain(reader,doc);
       if (!subQueryExpl.isMatch()) {
         return subQueryExpl;
       }
Index: src/java/org/apache/lucene/search/function/ValueSourceQuery.java
===================================================================
--- src/java/org/apache/lucene/search/function/ValueSourceQuery.java	(revision 806928)
+++ src/java/org/apache/lucene/search/function/ValueSourceQuery.java	(working copy)
@@ -98,7 +98,7 @@
     }
 
     /*(non-Javadoc) @see org.apache.lucene.search.Weight#explain(org.apache.lucene.index.IndexReader, int) */
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc) throws IOException {
+    public Explanation explain(IndexReader reader, int doc) throws IOException {
       return new ValueSourceScorer(similarity, reader, this).explain(doc);
     }
   }
Index: src/java/org/apache/lucene/search/spans/SpanWeight.java
===================================================================
--- src/java/org/apache/lucene/search/spans/SpanWeight.java	(revision 806928)
+++ src/java/org/apache/lucene/search/spans/SpanWeight.java	(working copy)
@@ -68,7 +68,7 @@
         .norms(query.getField()));
   }
 
-  public Explanation explain(Searcher searcher, IndexReader reader, int doc)
+  public Explanation explain(IndexReader reader, int doc)
     throws IOException {
 
     ComplexExplanation result = new ComplexExplanation();
Index: src/test/org/apache/lucene/search/JustCompileSearch.java
===================================================================
--- src/test/org/apache/lucene/search/JustCompileSearch.java	(revision 806928)
+++ src/test/org/apache/lucene/search/JustCompileSearch.java	(working copy)
@@ -425,7 +425,7 @@
 
   static final class JustCompileWeight extends Weight {
 
-    public Explanation explain(Searcher searcher, IndexReader reader, int doc) throws IOException {
+    public Explanation explain(IndexReader reader, int doc) throws IOException {
       throw new UnsupportedOperationException(UNSUPPORTED_MSG);
     }
 
Index: src/test/org/apache/lucene/search/TestPhraseQuery.java
===================================================================
--- src/test/org/apache/lucene/search/TestPhraseQuery.java	(revision 806928)
+++ src/test/org/apache/lucene/search/TestPhraseQuery.java	(working copy)
@@ -113,6 +113,7 @@
     query.add(new Term("field", "four"));
     query.add(new Term("field", "five"));
     ScoreDoc[] hits = searcher.search(query, null, 1000).scoreDocs;
+    System.out.println(searcher.explain(query, 0));
     assertEquals("exact match", 1, hits.length);
     QueryUtils.check(query,searcher);
 
Index: src/test/org/apache/lucene/search/TestTermScorer.java
===================================================================
--- src/test/org/apache/lucene/search/TestTermScorer.java	(revision 806928)
+++ src/test/org/apache/lucene/search/TestTermScorer.java	(working copy)
@@ -169,6 +169,7 @@
                                        indexReader.termDocs(allTerm), indexSearcher.getSimilarity(),
                                        indexReader.norms(FIELD));
         Explanation explanation = ts.explain(0);
+        System.out.println("exlain:" + weight.explain(indexReader, 0));
         assertTrue("explanation is null and it shouldn't be", explanation != null);
         //System.out.println("Explanation: " + explanation.toString());
         //All this Explain does is return the term frequency
@@ -193,6 +194,7 @@
         assertTrue("term frq: " + explanation.getValue() + " is not the square root of 2", explanation.getValue() == sqrtTwo);
 
         explanation = ts.explain(10);//try a doc out of range
+
         assertTrue("explanation is null and it shouldn't be", explanation != null);
         //System.out.println("Explanation: " + explanation.toString());
         //All this Explain does is return the term frequency

