package com.senseidb.clue.commands;

import java.io.PrintStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.Query;

import com.senseidb.clue.ClueContext;
import com.senseidb.clue.util.MatchSomeDocsQuery;

public class IndexTrimCommand extends ClueCommand {

  public IndexTrimCommand(ClueContext ctx) {
    super(ctx);
  }

  @Override
  public String getName() {
    return "trim";
  }

  @Override
  public String help() {
    return "trims the index, <TRIM PERCENTAGE> <OPTIONS>, options are: head, tail, random"; 
  }
  
  private static final Set<String> SUPPORTED_OPTIONS = new HashSet<String>(
      Arrays.asList("head", "tail", "random"));
  
  static int[] getDocsToDelete(int maxDoc, int numDocsToDelete, String option) {
    option = option.toLowerCase();
    if (SUPPORTED_OPTIONS.contains(option)) {
      int[] docs = new int[numDocsToDelete];
      if ("head".equals(option) || "tail".equals(option)) {        
        int start = "head".equals(option) ? 0 : maxDoc - numDocsToDelete;
        for (int i = 0; i < numDocsToDelete; ++i ) {
          docs[i] = i + start;
        }
      }
      else {
        // random case
        HashSet<Integer> docsToDelete = new HashSet<Integer>(numDocsToDelete);
        Random rand = new Random();
        while (docsToDelete.size() < numDocsToDelete) {
          int docid = rand.nextInt(maxDoc);
          docsToDelete.add(docid);
        }
        int i = 0;
        for (Integer docid : docsToDelete) {
          docs[i++] = docid;
        }
        Arrays.sort(docs);
      }
      return docs;
    }
    else {
      throw new IllegalArgumentException("trim option: " + option + " not supported");
    }
  }
  
  private static Query buildDeleteQuery(final int percentToDelete) {
    assert percentToDelete >= 0 && percentToDelete <= 100;
    final Random rand = new Random();
    return new MatchSomeDocsQuery() {
      
      @Override
      public String toString(String field) {
        return null;
      }
      
      @Override
      protected boolean match(int docId) {
        int guess = rand.nextInt(100);
        if (guess < percentToDelete) {
          return true;
        }
        return false;
      }
    };
    
  }

  @Override
  public void execute(String[] args, PrintStream out) throws Exception {
    if (args.length < 2) {
      out.println("usage: <TRIM PERCENTAGE> <OPTIONS>");
      return;
    }
    
    int trimPercent = Integer.parseInt(args[0]);
    
    if (trimPercent < 0 || trimPercent > 100) {
      throw new IllegalArgumentException("invalid percent: " + trimPercent);
    }
    
    IndexWriter writer = ctx.getIndexWriter();    
    if (writer != null) {
      out.println("force merge, expunge all deletes");
      writer.forceMerge(1);
      writer.commit();
      out.println("force merge successful into 1 segment");
      
      IndexReader reader = ctx.getIndexReader();
      
      writer.deleteDocuments(buildDeleteQuery(trimPercent));
      writer.commit();
      writer.forceMerge(1);
      writer.commit();
      ctx.refreshReader();
      reader = ctx.getIndexReader();
      out.println("trim successful, index now contains: " + reader.numDocs() + " docs.");
    }
    else {
      out.println("unable to open writer, index is in readonly mode");
    }
  }

}

@@ -79,87 +79,14 @@
 til.
-Arrays;%0Aimport java.util.HashSet;%0Aimport java.util.Random;%0Aimport java.util.Set
+Random
 ;%0A%0Ai
@@ -571,1202 +571,11 @@
 AGE%3E
- %3COPTIONS%3E, options are: head, tail, random%22; %0A  %7D%0A  %0A  private static final Set%3CString%3E SUPPORTED_OPTIONS = new HashSet%3CString%3E(%0A      Arrays.asList(%22head%22, %22tail%22, %22random%22));%0A  %0A  static int%5B%5D getDocsToDelete(int maxDoc, int numDocsToDelete, String option) %7B%0A    option = option.toLowerCase();%0A    if (SUPPORTED_OPTIONS.contains(option)) %7B%0A      int%5B%5D docs = new int%5BnumDocsToDelete%5D;%0A      if (%22head%22.equals(option) %7C%7C %22tail%22.equals(option)) %7B        %0A        int start = %22head%22.equals(option) ? 0 : maxDoc - numDocsToDelete;%0A        for (int i = 0; i %3C numDocsToDelete; ++i ) %7B%0A          docs%5Bi%5D = i + start;%0A        %7D%0A      %7D%0A      else %7B%0A        // random case%0A        HashSet%3CInteger%3E docsToDelete = new HashSet%3CInteger%3E(numDocsToDelete);%0A        Random rand = new Random();%0A        while (docsToDelete.size() %3C numDocsToDelete) %7B%0A          int docid = rand.nextInt(maxDoc);%0A          docsToDelete.add(docid);%0A        %7D%0A        int i = 0;%0A        for (Integer docid : docsToDelete) %7B%0A          docs%5Bi++%5D = docid;%0A        %7D%0A        Arrays.sort(docs);%0A      %7D%0A      return docs;%0A    %7D%0A    else %7B%0A      throw new IllegalArgumentException(%22trim option: %22 + option + %22 not supported%22);%0A    %7D
+%22; 
 %0A  %7D
@@ -1214,9 +1214,9 @@
 h %3C 
-2
+1
 ) %7B%0A
@@ -1262,18 +1262,8 @@
 AGE%3E
- %3COPTIONS%3E
 %22);%0A
@@ -1557,175 +1557,8 @@
 l) %7B
-%0A      out.println(%22force merge, expunge all deletes%22);%0A      writer.forceMerge(1);%0A      writer.commit();%0A      out.println(%22force merge successful into 1 segment%22);%0A
     
@@ -1703,59 +1703,14 @@
 t();
-%0A      writer.forceMerge(1);%0A      writer.commit();
+      
 %0A   

clean index trim command