// Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).

package org.rocksdb.util;

import org.junit.Test;
import org.rocksdb.*;
import org.rocksdb.Comparator;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;

import static org.junit.Assert.*;

/**
 * This is a direct port of various C++
 * tests from db/comparator_db_test.cc
 * and some code to adapt it to RocksJava
 */
public class BytewiseComparatorTest {

  /**
   * Open the database using the C++ BytewiseComparatorImpl
   * and test the results against our Java BytewiseComparator
   */
  @Test
  public void java_vs_cpp_bytewiseComparator()
      throws IOException, RocksDBException {
    for(int rand_seed = 301; rand_seed < 306; rand_seed++) {
      final Path dbDir = Files.createTempDirectory("comparator_db_test");
      try(final RocksDB db = openDatabase(dbDir,
          BuiltinComparator.BYTEWISE_COMPARATOR)) {
        final Random rnd = new Random(rand_seed);
        doRandomIterationTest(
            db,
            toJavaComparator(new BytewiseComparator(new ComparatorOptions())),
            Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"),
            rnd,
            8, 100, 3
        );
      } finally {
        removeData(dbDir);
      }
    }
  }

  /**
   * Open the database using the Java BytewiseComparator
   * and test the results against another Java BytewiseComparator
   */
  @Test
  public void java_vs_java_bytewiseComparator()
      throws IOException, RocksDBException {
    for(int rand_seed = 301; rand_seed < 306; rand_seed++) {
      final Path dbDir = Files.createTempDirectory("comparator_db_test");
      try(final RocksDB db = openDatabase(dbDir, new BytewiseComparator(
          new ComparatorOptions()))) {
        final Random rnd = new Random(rand_seed);
        doRandomIterationTest(
            db,
            toJavaComparator(new BytewiseComparator(new ComparatorOptions())),
            Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"),
            rnd,
            8, 100, 3
        );
      } finally {
        removeData(dbDir);
      }
    }
  }

  /**
   * Open the database using the C++ BytewiseComparatorImpl
   * and test the results against our Java DirectBytewiseComparator
   */
  @Test
  public void java_vs_cpp_directBytewiseComparator()
      throws IOException, RocksDBException {
    for(int rand_seed = 301; rand_seed < 306; rand_seed++) {
      final Path dbDir = Files.createTempDirectory("comparator_db_test");
      try(final RocksDB db = openDatabase(dbDir,
          BuiltinComparator.BYTEWISE_COMPARATOR)) {
        final Random rnd = new Random(rand_seed);
        doRandomIterationTest(
            db,
            toJavaComparator(new DirectBytewiseComparator(
                new ComparatorOptions())
            ),
            Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"),
            rnd,
            8, 100, 3
        );
      } finally {
        removeData(dbDir);
      }
    }
  }

  /**
   * Open the database using the Java DirectBytewiseComparator
   * and test the results against another Java DirectBytewiseComparator
   */
  @Test
  public void java_vs_java_directBytewiseComparator()
      throws IOException, RocksDBException {
    for(int rand_seed = 301; rand_seed < 306; rand_seed++) {
      final Path dbDir = Files.createTempDirectory("comparator_db_test");
      try(final RocksDB db = openDatabase(dbDir, new DirectBytewiseComparator(
            new ComparatorOptions()))) {
        final Random rnd = new Random(rand_seed);
        doRandomIterationTest(
            db,
            toJavaComparator(new DirectBytewiseComparator(
                new ComparatorOptions())
            ),
            Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"),
            rnd,
            8, 100, 3
        );
      } finally {
        removeData(dbDir);
      }
    }
  }

  /**
   * Open the database using the C++ ReverseBytewiseComparatorImpl
   * and test the results against our Java ReverseBytewiseComparator
   */
  @Test
  public void java_vs_cpp_reverseBytewiseComparator()
      throws IOException, RocksDBException {
    for(int rand_seed = 301; rand_seed < 306; rand_seed++) {
      final Path dbDir = Files.createTempDirectory("comparator_db_test");
      try(final RocksDB db = openDatabase(dbDir,
          BuiltinComparator.REVERSE_BYTEWISE_COMPARATOR)) {
        final Random rnd = new Random(rand_seed);
        doRandomIterationTest(
            db,
            toJavaComparator(
                new ReverseBytewiseComparator(new ComparatorOptions())
            ),
            Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"),
            rnd,
            8, 100, 3
        );
      } finally {
        removeData(dbDir);
      }
    }
  }

  /**
   * Open the database using the Java ReverseBytewiseComparator
   * and test the results against another Java ReverseBytewiseComparator
   */
  @Test
  public void java_vs_java_reverseBytewiseComparator()
      throws IOException, RocksDBException {

    for(int rand_seed = 301; rand_seed < 306; rand_seed++) {
      final Path dbDir = Files.createTempDirectory("comparator_db_test");
      try(final RocksDB db = openDatabase(dbDir, new ReverseBytewiseComparator(
            new ComparatorOptions()))) {
        final Random rnd = new Random(rand_seed);
        doRandomIterationTest(
            db,
            toJavaComparator(
                new ReverseBytewiseComparator(new ComparatorOptions())
            ),
            Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"),
            rnd,
            8, 100, 3
        );
      } finally {
        removeData(dbDir);
      }
    }
  }

  private void doRandomIterationTest(
      final RocksDB db, final java.util.Comparator<String> javaComparator,
      final List<String> source_strings, final Random rnd,
      final int num_writes, final int num_iter_ops,
      final int num_trigger_flush) throws RocksDBException {

    final TreeMap<String, String> map = new TreeMap<>(javaComparator);

    for (int i = 0; i < num_writes; i++) {
      if (num_trigger_flush > 0 && i != 0 && i % num_trigger_flush == 0) {
        db.flush(new FlushOptions());
      }

      final int type = rnd.nextInt(2);
      final int index = rnd.nextInt(source_strings.size());
      final String key = source_strings.get(index);
      switch (type) {
        case 0:
          // put
          map.put(key, key);
          db.put(new WriteOptions(), bytes(key), bytes(key));
          break;
        case 1:
          // delete
          if (map.containsKey(key)) {
            map.remove(key);
          }
          db.remove(new WriteOptions(), bytes(key));
          break;

        default:
          fail("Should not be able to generate random outside range 1..2");
      }
    }

    try(final RocksIterator iter = db.newIterator(new ReadOptions())) {
      final KVIter<String, String> result_iter = new KVIter(map);

      boolean is_valid = false;
      for (int i = 0; i < num_iter_ops; i++) {
        // Random walk and make sure iter and result_iter returns the
        // same key and value
        final int type = rnd.nextInt(6);
        iter.status();
        switch (type) {
          case 0:
            // Seek to First
            iter.seekToFirst();
            result_iter.seekToFirst();
            break;
          case 1:
            // Seek to last
            iter.seekToLast();
            result_iter.seekToLast();
            break;
          case 2: {
            // Seek to random key
            final int key_idx = rnd.nextInt(source_strings.size());
            final String key = source_strings.get(key_idx);
            iter.seek(bytes(key));
            result_iter.seek(bytes(key));
            break;
          }
          case 3:
            // Next
            if (is_valid) {
              iter.next();
              result_iter.next();
            } else {
              continue;
            }
            break;
          case 4:
            // Prev
            if (is_valid) {
              iter.prev();
              result_iter.prev();
            } else {
              continue;
            }
            break;
          default: {
            assert (type == 5);
            final int key_idx = rnd.nextInt(source_strings.size());
            final String key = source_strings.get(key_idx);
            final byte[] result = db.get(new ReadOptions(), bytes(key));
            if (!map.containsKey(key)) {
              assertNull(result);
            } else {
              assertArrayEquals(bytes(map.get(key)), result);
            }
            break;
          }
        }

        assertEquals(result_iter.isValid(), iter.isValid());

        is_valid = iter.isValid();

        if (is_valid) {
          assertArrayEquals(bytes(result_iter.key()), iter.key());

          //note that calling value on a non-valid iterator from the Java API
          //results in a SIGSEGV
          assertArrayEquals(bytes(result_iter.value()), iter.value());
        }
      }
    }
  }

  /**
   * Open the database using a C++ Comparator
   */
  private RocksDB openDatabase(
      final Path dbDir, final BuiltinComparator cppComparator)
      throws IOException, RocksDBException {
    final Options options = new Options()
        .setCreateIfMissing(true)
        .setComparator(cppComparator);
    return RocksDB.open(options, dbDir.toAbsolutePath().toString());
  }

  /**
   * Open the database using a Java Comparator
   */
  private RocksDB openDatabase(
      final Path dbDir,
      final AbstractComparator<? extends AbstractSlice<?>> javaComparator)
      throws IOException, RocksDBException {
    final Options options = new Options()
        .setCreateIfMissing(true)
        .setComparator(javaComparator);
    return RocksDB.open(options, dbDir.toAbsolutePath().toString());
  }

  private void closeDatabase(final RocksDB db) {
    db.close();
  }

  private void removeData(final Path dbDir) throws IOException {
    Files.walkFileTree(dbDir, new SimpleFileVisitor<Path>() {
      @Override
      public FileVisitResult visitFile(
          final Path file, final BasicFileAttributes attrs)
          throws IOException {
        Files.delete(file);
        return FileVisitResult.CONTINUE;
      }

      @Override
      public FileVisitResult postVisitDirectory(
          final Path dir, final IOException exc) throws IOException {
        Files.delete(dir);
        return FileVisitResult.CONTINUE;
      }
    });
  }

  private byte[] bytes(final String s) {
    return s.getBytes(StandardCharsets.UTF_8);
  }

  private java.util.Comparator<String> toJavaComparator(
      final Comparator rocksComparator) {
    return new java.util.Comparator<String>() {
      @Override
      public int compare(final String s1, final String s2) {
        return rocksComparator.compare(new Slice(s1), new Slice(s2));
      }
    };
  }

  private java.util.Comparator<String> toJavaComparator(
      final DirectComparator rocksComparator) {
    return new java.util.Comparator<String>() {
      @Override
      public int compare(final String s1, final String s2) {
        return rocksComparator.compare(new DirectSlice(s1),
            new DirectSlice(s2));
      }
    };
  }

  private class KVIter<K, V> implements RocksIteratorInterface {

    private final List<Map.Entry<K, V>> entries;
    private final java.util.Comparator<? super K> comparator;
    private int offset = -1;

    private int lastPrefixMatchIdx = -1;
    private int lastPrefixMatch = 0;

    public KVIter(final TreeMap<K, V> map) {
      this.entries = new ArrayList<>();
      final Iterator<Map.Entry<K, V>> iterator = map.entrySet().iterator();
      while(iterator.hasNext()) {
        entries.add(iterator.next());
      }
      this.comparator = map.comparator();
    }


    @Override
    public boolean isValid() {
      return offset > -1 && offset < entries.size();
    }

    @Override
    public void seekToFirst() {
      offset = 0;
    }

    @Override
    public void seekToLast() {
      offset = entries.size() - 1;
    }

    @Override
    public void seek(final byte[] target) {
      for(offset = 0; offset < entries.size(); offset++) {
        if(comparator.compare(entries.get(offset).getKey(),
            (K)new String(target, StandardCharsets.UTF_8)) >= 0) {
          return;
        }
      }
    }

    /**
     * Is `a` a prefix of `b`
     *
     * @return The length of the matching prefix, or 0 if it is not a prefix
     */
    private int isPrefix(final byte[] a, final byte[] b) {
      if(b.length >= a.length) {
        for(int i = 0; i < a.length; i++) {
          if(a[i] != b[i]) {
            return i;
          }
        }
        return a.length;
      } else {
        return 0;
      }
    }

    @Override
    public void next() {
      if(offset < entries.size()) {
        offset++;
      }
    }

    @Override
    public void prev() {
      if(offset >= 0) {
        offset--;
      }
    }

    @Override
    public void status() throws RocksDBException {
      if(offset < 0 || offset >= entries.size()) {
        throw new RocksDBException("Index out of bounds. Size is: " +
            entries.size() + ", offset is: " + offset);
      }
    }

    public K key() {
      if(!isValid()) {
        if(entries.isEmpty()) {
          return (K)"";
        } else if(offset == -1){
          return entries.get(0).getKey();
        } else if(offset == entries.size()) {
          return entries.get(offset - 1).getKey();
        } else {
          return (K)"";
        }
      } else {
        return entries.get(offset).getKey();
      }
    }

    public V value() {
      if(!isValid()) {
        return (V)"";
      } else {
        return entries.get(offset).getValue();
      }
    }
  }
}
