// Path: src/main/java/com/greplin/lucene/predicate/BitsProvider.java
// public abstract class BitsProvider {
// 
//   /**
//    * Gets the relevant bits for the given IndexReader.
//    * @param reader the reader.
//    * @return the bits for the given reader.
//    * @throws IOException if IO issues occur.
//    */
//   public abstract Bits get(IndexReader reader) throws IOException;
// 
// 
//   /**
//    * Get the object whose identity (not hashCode/equals) will be used for
//    * keying caches with this bits provider.
//    * @return the cache key.
//    */
//   public Object getCacheKey() {
//     return this;
//   }
// 
// }
// 
// Path: src/main/java/com/greplin/lucene/predicate/PredicateDocIdSet.java
// public class PredicateDocIdSet extends DocIdSet {
// 
//   /**
//    * The underlying doc id set.
//    */
//   private final DocIdSet docIdSet;
// 
// 
//   /**
//    * The predicate to match against.
//    */
//   private final Bits predicate;
// 
// 
//   /**
//    * Creates a predicate filter.
//    * @param docIdSet the doc id set to filter.
//    * @param predicate the predicate.
//    */
//   public PredicateDocIdSet(final DocIdSet docIdSet,
//                            final Bits predicate) {
//     this.docIdSet = docIdSet;
//     this.predicate = predicate;
//   }
// 
// 
//   @Override
//   public DocIdSetIterator iterator() throws IOException {
//     DocIdSetIterator iterator = this.docIdSet.iterator();
//     return iterator == null
//         ? null
//         :  new PredicateDocIdSetIterator(iterator, this.predicate);
//   }
// 
// 
//   /**
//    * Wraps a doc id set iterator with a predicate.
//    */
//   private static final class PredicateDocIdSetIterator
//       extends DocIdSetIterator {
// 
//     /**
//      * The iterator to filter.
//      */
//     private final DocIdSetIterator iterator;
// 
// 
//     /**
//      * The predicate ot match against.
//      */
//     private final Bits predicate;
// 
// 
//     /**
//      * Creates a filtered doc id set iterator.
//      * @param iterator the underlying iterator.
//      * @param predicate the predicate to filter with.
//      */
//     private PredicateDocIdSetIterator(final DocIdSetIterator iterator,
//                                       final Bits predicate) {
//       this.iterator = iterator;
//       this.predicate = predicate;
//     }
// 
// 
//     @Override
//     public int docID() {
//       return this.iterator.docID();
//     }
// 
// 
//     @Override
//     public int nextDoc() throws IOException {
//       for (;;) {
//         int next = this.iterator.nextDoc();
//         if (next == NO_MORE_DOCS || this.predicate.get(next)) {
//           return next;
//         }
//       }
//     }
// 
// 
//     @Override
//     public int advance(final int target) throws IOException {
//       int docId = this.iterator.advance(target);
//       if (docId == NO_MORE_DOCS || this.predicate.get(docId)) {
//         return docId;
//       } else {
//         return nextDoc();
//       }
//     }
// 
//   }
// }


import com.google.common.base.Objects;
import com.greplin.lucene.predicate.BitsProvider;
import com.greplin.lucene.predicate.PredicateDocIdSet;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import java.io.IOException;
/*
 * Copyright 2012 Greplin, Inc. All Rights Reserved.
 */

package com.greplin.lucene.filter;



/**
 * A filter that is further filtered by a predicate.
 */
public class PredicateFilter extends Filter {

  /**
   * The underlying filter.
   */
  private final Filter filter;


  /**
   * The predicate to match against.
   */
  private final BitsProvider predicate;


  /**
   * Creates a predicate filter.
   * @param filter the filter to further filter.
   * @param predicate the predicate.
   */
  public PredicateFilter(final Filter filter, final BitsProvider predicate) {
    assert filter != null;
    assert predicate != null;
    this.filter = filter;
    this.predicate = predicate;
  }


// Path: src/main/java/com/greplin/lucene/predicate/BitsProvider.java
// public abstract class BitsProvider {
// 
//   /**
//    * Gets the relevant bits for the given IndexReader.
//    * @param reader the reader.
//    * @return the bits for the given reader.
//    * @throws IOException if IO issues occur.
//    */
//   public abstract Bits get(IndexReader reader) throws IOException;
// 
// 
//   /**
//    * Get the object whose identity (not hashCode/equals) will be used for
//    * keying caches with this bits provider.
//    * @return the cache key.
//    */
//   public Object getCacheKey() {
//     return this;
//   }
// 
// }
// 
// Path: src/main/java/com/greplin/lucene/predicate/PredicateDocIdSet.java
// public class PredicateDocIdSet extends DocIdSet {
// 
//   /**
//    * The underlying doc id set.
//    */
//   private final DocIdSet docIdSet;
// 
// 
//   /**
//    * The predicate to match against.
//    */
//   private final Bits predicate;
// 
// 
//   /**
//    * Creates a predicate filter.
//    * @param docIdSet the doc id set to filter.
//    * @param predicate the predicate.
//    */
//   public PredicateDocIdSet(final DocIdSet docIdSet,
//                            final Bits predicate) {
//     this.docIdSet = docIdSet;
//     this.predicate = predicate;
//   }
// 
// 
//   @Override
//   public DocIdSetIterator iterator() throws IOException {
//     DocIdSetIterator iterator = this.docIdSet.iterator();
//     return iterator == null
//         ? null
//         :  new PredicateDocIdSetIterator(iterator, this.predicate);
//   }
// 
// 
//   /**
//    * Wraps a doc id set iterator with a predicate.
//    */
//   private static final class PredicateDocIdSetIterator
//       extends DocIdSetIterator {
// 
//     /**
//      * The iterator to filter.
//      */
//     private final DocIdSetIterator iterator;
// 
// 
//     /**
//      * The predicate ot match against.
//      */
//     private final Bits predicate;
// 
// 
//     /**
//      * Creates a filtered doc id set iterator.
//      * @param iterator the underlying iterator.
//      * @param predicate the predicate to filter with.
//      */
//     private PredicateDocIdSetIterator(final DocIdSetIterator iterator,
//                                       final Bits predicate) {
//       this.iterator = iterator;
//       this.predicate = predicate;
//     }
// 
// 
//     @Override
//     public int docID() {
//       return this.iterator.docID();
//     }
// 
// 
//     @Override
//     public int nextDoc() throws IOException {
//       for (;;) {
//         int next = this.iterator.nextDoc();
//         if (next == NO_MORE_DOCS || this.predicate.get(next)) {
//           return next;
//         }
//       }
//     }
// 
// 
//     @Override
//     public int advance(final int target) throws IOException {
//       int docId = this.iterator.advance(target);
//       if (docId == NO_MORE_DOCS || this.predicate.get(docId)) {
//         return docId;
//       } else {
//         return nextDoc();
//       }
//     }
// 
//   }
// }


// Path: src/main/java/com/greplin/lucene/filter/PredicateFilter.java
import com.google.common.base.Objects;
import com.greplin.lucene.predicate.BitsProvider;
import com.greplin.lucene.predicate.PredicateDocIdSet;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import java.io.IOException;

/*
 * Copyright 2012 Greplin, Inc. All Rights Reserved.
 */

package com.greplin.lucene.filter;



/**
 * A filter that is further filtered by a predicate.
 */
public class PredicateFilter extends Filter {

  /**
   * The underlying filter.
   */
  private final Filter filter;


  /**
   * The predicate to match against.
   */
  private final BitsProvider predicate;


  /**
   * Creates a predicate filter.
   * @param filter the filter to further filter.
   * @param predicate the predicate.
   */
  public PredicateFilter(final Filter filter, final BitsProvider predicate) {
    assert filter != null;
    assert predicate != null;
    this.filter = filter;
    this.predicate = predicate;
  }


  @Override