/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.drill.exec.vector;

import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.common.types.TypeProtos.MinorType;
import org.apache.drill.common.types.Types;
import org.apache.drill.exec.memory.BufferAllocator;
import org.apache.drill.exec.memory.RootAllocatorFactory;
import org.apache.drill.exec.record.MaterializedField;
import org.apache.drill.exec.record.TransferPair;
import org.apache.drill.exec.vector.NullableVarCharVector.Accessor;
import org.apache.drill.test.BaseTest;
import org.junit.Test;

import java.nio.charset.StandardCharsets;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertArrayEquals;


public class TestSplitAndTransfer extends BaseTest {
  @Test
  public void test() throws Exception {
    final DrillConfig drillConfig = DrillConfig.create();
    final BufferAllocator allocator = RootAllocatorFactory.newRoot(drillConfig);
    final MaterializedField field = MaterializedField.create("field", Types.optional(MinorType.VARCHAR));
    final NullableVarCharVector varCharVector = new NullableVarCharVector(field, allocator);
    varCharVector.allocateNew(10000, 1000);

    final int valueCount = 500;
    final String[] compareArray = new String[valueCount];

    final NullableVarCharVector.Mutator mutator = varCharVector.getMutator();
    for (int i = 0; i < valueCount; i += 3) {
      final String s = String.format("%010d", i);
      mutator.set(i, s.getBytes(StandardCharsets.UTF_8));
      compareArray[i] = s;
    }
    mutator.setValueCount(valueCount);

    final TransferPair tp = varCharVector.getTransferPair(allocator);
    final NullableVarCharVector newVarCharVector = (NullableVarCharVector) tp.getTo();
    final Accessor accessor = newVarCharVector.getAccessor();
    final int[][] startLengths = {{0, 201}, {201, 200}, {401, 99}};

    for (final int[] startLength : startLengths) {
      final int start = startLength[0];
      final int length = startLength[1];
      tp.splitAndTransfer(start, length);
      newVarCharVector.getMutator().setValueCount(length);
      for (int i = 0; i < length; i++) {
        final boolean expectedSet = ((start + i) % 3) == 0;
        if (expectedSet) {
          final byte[] expectedValue = compareArray[start + i].getBytes(StandardCharsets.UTF_8);
          assertFalse(accessor.isNull(i));
          assertArrayEquals(expectedValue, accessor.get(i));
        } else {
          assertTrue(accessor.isNull(i));
        }
      }
      newVarCharVector.clear();
    }

    varCharVector.close();
    allocator.close();
  }

  /**
   *  BitVector tests
   */

  enum TestBitPattern {
    ZERO,
    ONE,
    ALTERNATING,
    RANDOM
  }

  @Test
  public void testBitVectorUnalignedStart() throws Exception {

    testBitVectorImpl(16, new int[][] {{2, 4}}, TestBitPattern.RANDOM);
    testBitVectorImpl(16, new int[][] {{2, 4}}, TestBitPattern.ONE);
    testBitVectorImpl(16, new int[][] {{2, 4}}, TestBitPattern.ZERO);
    testBitVectorImpl(16, new int[][] {{2, 4}}, TestBitPattern.ALTERNATING);

    testBitVectorImpl(4096, new int[][] {{4092, 4}}, TestBitPattern.ONE);
    testBitVectorImpl(4096, new int[][] {{4092, 4}}, TestBitPattern.ZERO);
    testBitVectorImpl(4096, new int[][] {{4092, 4}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(4096, new int[][] {{4092, 4}}, TestBitPattern.RANDOM);

    testBitVectorImpl(4096, new int[][] {{1020, 8}}, TestBitPattern.ONE);
    testBitVectorImpl(4096, new int[][] {{1020, 8}}, TestBitPattern.ZERO);
    testBitVectorImpl(4096, new int[][] {{1020, 8}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(4096, new int[][] {{1020, 8}}, TestBitPattern.RANDOM);

    testBitVectorImpl(24, new int[][] {{5, 17}}, TestBitPattern.ONE);
    testBitVectorImpl(24, new int[][] {{5, 17}}, TestBitPattern.ZERO);
    testBitVectorImpl(24, new int[][] {{5, 17}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(24, new int[][] {{5, 17}}, TestBitPattern.RANDOM);

    testBitVectorImpl(3443, new int[][] {{0, 2047}, {2047, 1396}}, TestBitPattern.ZERO);
    testBitVectorImpl(3443, new int[][] {{0, 2047}, {2047, 1396}}, TestBitPattern.ONE);
    testBitVectorImpl(3443, new int[][] {{0, 2047}, {2047, 1396}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(3443, new int[][] {{0, 2047}, {2047, 1396}}, TestBitPattern.RANDOM);

    testBitVectorImpl(3447, new int[][] {{0, 2047}, {2047, 1400}}, TestBitPattern.ZERO);
    testBitVectorImpl(3447, new int[][] {{0, 2047}, {2047, 1400}}, TestBitPattern.ONE);
    testBitVectorImpl(3447, new int[][] {{0, 2047}, {2047, 1400}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(3447, new int[][] {{0, 2047}, {2047, 1400}}, TestBitPattern.RANDOM);
  }

  @Test
  public void testBitVectorAlignedStart() throws Exception {

    testBitVectorImpl(32, new int[][] {{0, 4}}, TestBitPattern.RANDOM);
    testBitVectorImpl(32, new int[][] {{0, 4}}, TestBitPattern.ONE);
    testBitVectorImpl(32, new int[][] {{0, 4}}, TestBitPattern.ZERO);
    testBitVectorImpl(32, new int[][] {{0, 4}}, TestBitPattern.ALTERNATING);


    testBitVectorImpl(32, new int[][] {{0, 8}}, TestBitPattern.ONE);
    testBitVectorImpl(32, new int[][] {{0, 8}}, TestBitPattern.ZERO);
    testBitVectorImpl(32, new int[][] {{0, 8}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(32, new int[][] {{0, 8}}, TestBitPattern.RANDOM);

    testBitVectorImpl(24, new int[][] {{0, 17}}, TestBitPattern.ONE);
    testBitVectorImpl(24, new int[][] {{0, 17}}, TestBitPattern.ZERO);
    testBitVectorImpl(24, new int[][] {{0, 17}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(24, new int[][] {{0, 17}}, TestBitPattern.RANDOM);

    testBitVectorImpl(3444, new int[][] {{0, 2048}, {2048, 1396}}, TestBitPattern.ZERO);
    testBitVectorImpl(3444, new int[][] {{0, 2048}, {2048, 1396}}, TestBitPattern.ONE);
    testBitVectorImpl(3444, new int[][] {{0, 2048}, {2048, 1396}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(3444, new int[][] {{0, 2048}, {2048, 1396}}, TestBitPattern.RANDOM);

    testBitVectorImpl(3448, new int[][] {{0, 2048}, {2048, 1400}}, TestBitPattern.ZERO);
    testBitVectorImpl(3448, new int[][] {{0, 2048}, {2048, 1400}}, TestBitPattern.ONE);
    testBitVectorImpl(3448, new int[][] {{0, 2048}, {2048, 1400}}, TestBitPattern.ALTERNATING);
    testBitVectorImpl(3448, new int[][] {{0, 2048}, {2048, 1400}}, TestBitPattern.RANDOM);
  }

  int getBit(TestBitPattern pattern, int index) {
    if (pattern == TestBitPattern.RANDOM) {
      return (int) (Math.random() * 2);
    }
    return (pattern == TestBitPattern.ALTERNATING) ? (index % 2) : ((pattern == TestBitPattern.ONE) ? 1 : 0);
  }

  public void testBitVectorImpl(int valueCount, final int[][] startLengths, TestBitPattern pattern) throws Exception {
    final DrillConfig drillConfig = DrillConfig.create();
    final BufferAllocator allocator = RootAllocatorFactory.newRoot(drillConfig);
    final MaterializedField field = MaterializedField.create("field", Types.optional(MinorType.BIT));
    final BitVector bitVector = new BitVector(field, allocator);
    bitVector.allocateNew(valueCount  + 8); // extra byte at the end that gets filled with junk
    final int[] compareArray = new int[valueCount];

    int testBitValue = 0;
    final BitVector.Mutator mutator = bitVector.getMutator();
    for (int i = 0; i < valueCount; i++) {
      testBitValue = getBit(pattern, i);
      mutator.set(i, testBitValue);
      compareArray[i] = testBitValue;
    }

    // write some junk value at the end to catch
    // off-by-one out-of-bound reads
    for (int j = valueCount; j < valueCount + 8; j++) {
      mutator.set(j, ~testBitValue); // fill with compliment of testBit
    }
    mutator.setValueCount(valueCount);

    final TransferPair tp = bitVector.getTransferPair(allocator);
    final BitVector newBitVector = (BitVector) tp.getTo();
    final BitVector.Accessor accessor = newBitVector.getAccessor();

    for (final int[] startLength : startLengths) {
      final int start = startLength[0];
      final int length = startLength[1];
      tp.splitAndTransfer(start, length);
      assertEquals(newBitVector.getAccessor().getValueCount(), length);
      for (int i = 0; i < length; i++) {
        final int expectedValue = compareArray[start + i];
        assertEquals(expectedValue, accessor.get(i));
      }
      newBitVector.clear();
    }
    bitVector.close();
    allocator.close();
  }
}
