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

package com.greplin.lucene.predicate;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.util.Bits;

import java.io.IOException;

/**
 * Common predicates.
 */
public final class Predicates {

  /** Not instantiable. */
  private Predicates() { }


  /**
   * Creates a new predicate bits provider that matches documents
   * matched by all of the arguments.
   * @param bitsProviders the sub-predicates.
   * @return a new predicate bits provider that matches documents
   * matched by all of the arguments.
   */
  public static BitsProvider and(final BitsProvider... bitsProviders) {
    BooleanBitsProvider result = new BooleanBitsProvider();
    for (BitsProvider provider : bitsProviders) {
      result.add(provider, BooleanClause.Occur.MUST);
    }
    return result;
  }


  /**
   * Creates a new predicate bits provider that matches documents
   * matched by any of the arguments.
   * @param bitsProviders the sub-predicates.
   * @return a new predicate bits provider that matches documents
   * matched by any of the arguments.
   */
  public static BitsProvider or(final BitsProvider... bitsProviders) {
    BooleanBitsProvider result = new BooleanBitsProvider();
    for (BitsProvider provider : bitsProviders) {
      result.add(provider, BooleanClause.Occur.SHOULD);
    }
    return result;
  }


  /**
   * Creates a new predicate bits provider that matches documents
   * not matched by the argument.
   * @param bitsProvider the predicate to negate.
   * @return a new predicate bits provider that matches documents
   * not matched by the argument.
   */
  public static BitsProvider not(final BitsProvider bitsProvider) {
    return new InverseBitsProvider(bitsProvider);
  }


  /**
   * BitsProvider that matches the opposite set of bits as its
   * argument.
   */
  private static final class InverseBitsProvider extends BitsProvider {

    /**
     * The original bits to negate.
     */
    private final BitsProvider original;


    /**
     * Creates a BitsProvider that negates its argument.
     * @param original the bits to negate.
     */
    private InverseBitsProvider(final BitsProvider original) {
      this.original = original;
    }


    @Override
    public Bits get(final IndexReader reader) throws IOException {
      return new InverseBits(this.original.get(reader));
    }

  }


  /**
   * Bits that matches the opposite set of bits as its argument.
   */
  private static final class InverseBits implements Bits {

    /**
     * The original bits to negate.
     */
    private final Bits original;


    /**
     * Creates Bits that negate the argument.
     * @param original the bits to negate.
     */
    private InverseBits(final Bits original) {
      this.original = original;
    }


    @Override
    public boolean get(final int index) {
      return !this.original.get(index);
    }


    @Override
    public int length() {
      return this.original.length();
    }

  }

}

@@ -3059,10 +3059,707 @@
 %7D%0A%0A  %7D%0A%0A
+%0A  /**%0A   * Predicate that matches no documents.%0A   */%0A  public static final BitsProvider NONE = new BitsProvider() %7B%0A    @Override%0A    public Bits get(final IndexReader reader) throws IOException %7B%0A      return new Predicate() %7B%0A        @Override%0A        public boolean get(final int index) %7B%0A          return false;%0A        %7D%0A      %7D;%0A    %7D%0A  %7D;%0A%0A%0A  /**%0A   * Predicate that matches all documents.%0A   */%0A  public static final BitsProvider ALL = new BitsProvider() %7B%0A    @Override%0A    public Bits get(final IndexReader reader) throws IOException %7B%0A      return new Predicate() %7B%0A        @Override%0A        public boolean get(final int index) %7B%0A          return true;%0A        %7D%0A      %7D;%0A    %7D%0A  %7D;%0A%0A
 %7D%0A

Add simple match everything / match nothing predicates