package binaryData;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static binaryData.TradeFactory.create;

class Main {
  public static final int million = 1_000_000;
  public static final int tenMillion = 10_000_000;

  public static void main(String[] args) throws IOException, ClassNotFoundException {
    System.out.println("---------  Object trade  ---------");
    List<ObjectTrade> objectTrades = create(million, ObjectTrade::new)
        .stream()
        .map(p -> (ObjectTrade) p)
        .collect(Collectors.toList());
    testObjectTrades(objectTrades);

    System.out.println();
    System.out.println("==================================");
    System.out.println();

    System.out.println("---------  Binary trade  ---------");
    List<BinaryTrade> binaryTrades = create(tenMillion, BinaryTrade::new)
        .stream()
        .map(p -> (BinaryTrade) p)
        .collect(Collectors.toList());
    testBinaryTrade(binaryTrades);
  }

  private static void testBinaryTrade(List<BinaryTrade> trades) throws IOException, ClassNotFoundException {
    runSimpleQuery(trades);

    System.gc();
    SerializationTest.checkSerialization(trades);

    System.gc();
    SerializationTest.checkBatchSerialization(trades);

    System.gc();
    SerializationTest.checkFileSerialization(trades, Paths.get("/Users/apple/depot/c24.io/binaryTrades.dat"));
  }

  private static void testObjectTrades(List<ObjectTrade> trades) throws IOException, ClassNotFoundException {
    runSimpleQuery(trades);

    System.gc();
    SerializationTest.checkSerialization(trades);

    System.gc();
    SerializationTest.checkBatchSerialization(trades);
  }

  public static <T extends ImmutableTrade> void runSimpleQuery(List<T> immutableTrades) {
    Comparator<ImmutableTrade> comparator = Comparator.comparing(ImmutableTrade::getExchangeRate);
    Predicate<ImmutableTrade> predicate = t -> t.getCurrency1().equalsIgnoreCase("GBP") &&
        t.getCurrency2().equalsIgnoreCase("USD") &&
        t.getBuySell().equalsIgnoreCase("Buy");

    final AtomicLong ignore = new AtomicLong(0);

    int n = 10;

    System.out.println("Running a filter and sort on the trades (" + n + " times)");
    long start = System.nanoTime();
    for (int i = 0; i < n; i++) {
      System.gc();

      immutableTrades.stream()
          .filter(predicate)
          .sorted(comparator)
          .limit(10)
          .forEach(p -> ignore.set(p.getId()));
    }

    System.out.println("ignore: " + ignore.get());
    System.out.printf("Query time = %.3f seconds%n%n", (System.nanoTime() - start) / 1e9);
  }

}

//    ---------  Object trade  ---------
//    Time to generate 1.0 million elements: 2.23 seconds
//    Running a filter and sort on the trades (10 times)
//    ignore: 660149
//    Query time = 7.731 seconds
//
//    Testing serialization...
//    Time to serialize/deserialize 1.0 million elements: 42.00 seconds
//    Serialized size: 667 bytes
//    Testing batch serialization...
//    Time to serialize/deserialize 1.0 million elements: 14.50 seconds
//    Serialized size: 174,361,024 bytes
//
//    ==================================
//
//    ---------  Binary trade  ---------
//    Time to generate 10.0 million elements: 29.60 seconds
//    Running a filter and sort on the trades (10 times)
//    ignore: 9225511
//    Query time = 29.641 seconds
//
//    Testing serialization...
//    Time to serialize/deserialize 10.0 million elements: 48.05 seconds
//    Serialized size: 85 bytes
//    Testing batch serialization...
//    Time to serialize/deserialize 10.0 million elements: 14.85 seconds
//    Serialized size: 480,000,091 bytes
//    Writing binary data to file ...
//    Time to write 10.0 million elements: 1.82 seconds
//
//    Reading binary data to file ...
//    Time to read 10.0 million elements: 3.01 seconds