package g1.search;

import g1.base.Configuration;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.FSDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Utilities of Lucene {@link IndexWriter}.
 */
public class IndexWriters {
    private static final Logger LOG = LoggerFactory.getLogger(
        IndexWriters.class
    );

    /**
     * Default index path.
     */
    @Configuration
    public static String indexPath = null;

    /**
     * Default RAM buffer size; Unit: MB.
     * <p>
     * This is larger than Lucene's default (16 MB), which should yield
     * higher batch indexing throughput.
     */
    @Configuration
    public static double ramBufferSize = 256.0d;

    /**
     * Flush after the number of buffered doc exceeds the limit.
     * <p>
     * We disable this feature by default.  Together with the
     * ramBufferSize above, the indexer only flushes when the buffer
     * size exceeds the limit, which should yield higher batch indexing
     * throughput.
     */
    @Configuration
    public static int maxBufferedDocs = IndexWriterConfig.DISABLE_AUTO_FLUSH;

    /**
     * Whether to force merge in {@link #close(IndexWriter)}.
     */
    @Configuration
    public static boolean forceMerge = true;

    private IndexWriters() {
        throw new AssertionError();
    }

    /**
     * Detect mode and open an {@link IndexWriter}.
     */
    public static IndexWriter open(Analyzer analyzer) throws IOException {
        return open(Paths.get(checkNotNull(indexPath)), analyzer);
    }

    /**
     * Detect mode and open an {@link IndexWriter}.
     */
    public static IndexWriter open(
        Path indexPath, Analyzer analyzer
    ) throws IOException {
        return Files.exists(indexPath) ?
            append(indexPath, analyzer) : create(indexPath, analyzer);
    }

    /**
     * Open an {@link IndexWriter} in {@code CREATE} mode.
     */
    public static IndexWriter create(
        Path indexPath, Analyzer analyzer
    ) throws IOException {
        LOG.atInfo().addArgument(indexPath).log("create index writer on {}");
        return open(indexPath, analyzer, IndexWriterConfig.OpenMode.CREATE);
    }

    /**
     * Open an {@link IndexWriter} in {@code APPEND} mode.
     */
    public static IndexWriter append(
        Path indexPath, Analyzer analyzer
    ) throws IOException {
        LOG.atInfo().addArgument(indexPath).log("append index writer on {}");
        return open(indexPath, analyzer, IndexWriterConfig.OpenMode.APPEND);
    }

    private static IndexWriter open(
        Path indexPath, Analyzer analyzer, IndexWriterConfig.OpenMode mode
    ) throws IOException {
        return new IndexWriter(
            FSDirectory.open(indexPath),
            applyConfig(new IndexWriterConfig(analyzer).setOpenMode(mode))
        );
    }

    public static IndexWriterConfig applyConfig(IndexWriterConfig config) {
        LOG.atInfo()
            .addArgument(ramBufferSize)
            .log("set RAM buffer size: {} MB");
        config.setRAMBufferSizeMB(ramBufferSize);
        LOG.atInfo()
            .addArgument(maxBufferedDocs)
            .log("set max buffered docs: {}");
        config.setMaxBufferedDocs(maxBufferedDocs);
        return config;
    }

    public static void close(IndexWriter writer) throws IOException {
        LOG.atInfo()
            .addArgument(writer.getDirectory())
            .log("close index writer on {}");
        if (forceMerge) {
            writer.forceMerge(/* maxNumSegments */ 1);
        }
        writer.close();
    }
}

@@ -817,112 +817,311 @@
   * 
-This is larger than Lucene's default (16 MB), which should yield%0A     * higher batch indexing throughput
+Although theoretically setting it to a larger value might yield%0A     * higher batch indexing throughput, our measurements show that the%0A     * default throughput is already very impressive.  Also, a larger%0A     * value might cause JVM to OOM.  So it might not be worthwhile to%0A     * increase this value
 .%0A  
@@ -1189,15 +1189,61 @@
 ze =
- 256.0d
+%0A        IndexWriterConfig.DEFAULT_RAM_BUFFER_SIZE_MB
 ;%0A%0A 
@@ -1339,218 +1339,93 @@
  We 
-disable this feature by default.  Together with the%0A     * ramBufferSize above, the indexer only flushes when the buffer%0A     * size exceeds the limit, which should yield higher batch indexing%0A     * throughput
+use Lucene's default for the same reason stated in%0A     * %7B@code ramBufferSize%7D above
 .%0A  
@@ -1488,16 +1488,24 @@
 edDocs =
+%0A       
  IndexWr
@@ -1520,25 +1520,32 @@
 ig.D
-ISABLE_AUTO_FLUSH
+EFAULT_MAX_BUFFERED_DOCS
 ;%0A%0A 

Use Lucene's default values based on our measurements