/*
# Make sure not to over-use our read capacity: free read capacity is 25k/s
# for index lookups (stats-only), each item is
#   install key: 39ed747039a83c9280 -- 18 bytes
#   time stamp: 1422408151.549 -- Number: 8 bytes?
# so probably 24 bytes, meaning we should be able to read 1000 items per second
# so we will
# - connect to dynamoDB
# - use paginated queries to download 500 items at a time
# - if a request took less than a second, wait until the second is over
# - write the data into a csv file for later
*/

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ReturnConsumedCapacity;
import com.amazonaws.services.dynamodbv2.model.ScanRequest;
import com.amazonaws.services.dynamodbv2.model.ScanResult;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Map;

import static java.lang.Math.max;
import static java.lang.Thread.sleep;

public class Main {

  // retrieve only this many per request
  private static int maxItems = 500;
  // this many requests per second
  private static double maxRequestRate = 1;

  private static void error(String err) {
    System.err.println(err);
    System.exit(2);
  }

  private static void statScan(String filename) {
    AmazonDynamoDBClient client = new AmazonDynamoDBClient(new ProfileCredentialsProvider());

    try {
      PrintWriter fo = new PrintWriter(filename);

      int nrequests = 0;
      int count = 0, totalCount = 0;
      double consumed = 0;
      long start = System.nanoTime(), last=start;

      Map<String, AttributeValue> lastKeyEvaluated = null;
      do {
        ScanRequest scanRequest = new ScanRequest()
          .withTableName("stats-only")
          .withLimit(maxItems)
          .withExclusiveStartKey(lastKeyEvaluated);

        scanRequest.setReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);

        ScanResult result = client.scan(scanRequest);

        System.out.println("got " + result.getCount() + "/" + result.getScannedCount() + " items using " + result.getConsumedCapacity().getCapacityUnits() + " capacity");

        nrequests++;
        count += result.getCount();
        totalCount += result.getScannedCount();
        consumed += result.getConsumedCapacity().getCapacityUnits();

        for (Map<String, AttributeValue> item : result.getItems()) {
          fo.println(item.get("install") + "," + item.get("time"));
        }
        lastKeyEvaluated = result.getLastEvaluatedKey();

        long next = System.nanoTime();
        try {
          sleep((int) (max(0., 1000./maxRequestRate - 1e-6 * (next - last))));
        } catch (InterruptedException e) {
          error("interrupted.");
        }
        last=next;
      } while (lastKeyEvaluated != null);

      double time = 1e-9*(System.nanoTime() - start);

      System.out.println("retrieved " + count + "/" + totalCount + " records in " + time + "seconds, using " + nrequests + " requests and " + consumed + " capacity.");
    } catch (FileNotFoundException e) {
      error("could not create file " + filename);
    }
  }

  private static void fullScan(String filename) {
    error("full retrieval not implemented.");
  }

  private static void usage() {
    System.out.println(
      "usage: accessDB stats|full <file>\n" +
      "Gets eddy usage data from dynamoDB and stores it in <file>.\n" +
      "  stats : get install IDs and times from the stats index and store as CSV\n" +
      "  full  : get all data and store as JSON. There's an additional guarantee that\n" +
      "          each row from the DB starts at a newline, and all rows except the first\n" +
      "          and last line are DB rows.");
  }

  public static void main(String[] args) {
    if (args.length < 3) {
      usage();
      return;
    }
    String filename = args[2];
    String command = args[1];

    if (command.equals("stats"))
      statScan(filename);
    else if (command.equals("full")) {
      fullScan(filename);
    } else {
      usage();
    }
  }
}

@@ -890,16 +890,56 @@
 nResult;
+%0Aimport com.sun.deploy.util.StringUtils;
 %0A%0Aimport
@@ -994,24 +994,49 @@
 rintWriter;%0A
+import java.util.Arrays;%0A
 import java.
@@ -3403,16 +3403,29 @@
 d usage(
+String%5B%5D args
 ) %7B%0A    
@@ -3484,16 +3484,72 @@
 l %3Cfile%3E
+ (got %22 + StringUtils.join(Arrays.asList(args),%22 %22) + %22)
 %5Cn%22 +%0A  
@@ -4006,17 +4006,17 @@
 ength %3C 
-3
+2
 ) %7B%0A    
@@ -4019,24 +4019,28 @@
       usage(
+args
 );%0A      ret
@@ -4077,17 +4077,17 @@
  = args%5B
-2
+1
 %5D;%0A    S
@@ -4107,17 +4107,17 @@
  = args%5B
-1
+0
 %5D;%0A%0A    
@@ -4261,16 +4261,20 @@
   usage(
+args
 );%0A    %7D

fix args for DB