/*
 * 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.carbondata.core.keygenerator.mdkey;

import java.io.Serializable;
import java.util.Arrays;

public class Bits implements Serializable {

  /**
   * Bits MAX_LENGTH
   */
  private static final int MAX_LENGTH = 63;
  private static final int LONG_LENGTH = 64;
  /**
   * serialVersionUID.
   */
  private static final long serialVersionUID = 1555114921503304849L;
  /**
   * LONG_MAX.
   */
  private static final long LONG_MAX = 0x7fffffffffffffffL;
  /**
   * length.
   */
  private int length = 100;
  /**
   * lens.
   */
  private int[] lens;
  /**
   * word size.
   */
  private int wSize;
  /**
   * byteSize.
   */
  private int byteSize;

  public Bits(int[] lens) {
    this.lens = lens;
    this.length = getTotalLength(lens);

    wSize = length / LONG_LENGTH;
    byteSize = length / 8;

    if (length % LONG_LENGTH != 0) {
      wSize++;
    }

    if (length % 8 != 0) {
      byteSize++;
    }
  }

  public int getByteSize() {
    return byteSize;
  }

  private int getTotalLength(int[] lens) {
    int tLen = 0;
    for (int len : lens) {
      tLen += len;
    }
    return tLen;
  }

  public int getDimCount() {
    return lens.length;
  }

  /**
   * Return the start and end Byte offsets of dimension in the MDKey. int []
   * {start, end}
   */
  public int[] getKeyByteOffsets(int index) {

    int priorLen = length % 8 == 0 ? 0 : (8 - length % 8);
    int start = 0;
    int end = 0;

    // Calculate prior length for all previous keys
    for (int i = 0; i < index; i++) {
      priorLen += lens[i];
    }

    // Start
    start = priorLen / 8;

    int tillKeyLength = priorLen + lens[index];

    // End key
    end = (tillKeyLength) / 8;

    // Consider if end is the last bit. No need to include the next byte.
    if (tillKeyLength % 8 == 0) {
      end--;
    }

    return new int[] { start, end };
  }

  protected long[] get(long[] keys) {
    long[] words = new long[wSize];
    int ll = 0;
    int minLength = Math.min(lens.length, keys.length);
    for (int i = minLength - 1; i >= 0; i--) {

      long val = keys[i];

      int idx = ll >> 6; // divide by 64 to get the new word index
      int position = ll & 0x3f; // to ignore sign bit and consider the remaining
      val = val & (LONG_MAX >> (MAX_LENGTH - lens[i])); // To control the
      // logic so that
      // any val do not
      // exceed the
      // cardinality
      long mask = (val << position);
      long word = words[idx];
      words[idx] = (word | mask);
      ll += lens[i];

      int nextIndex = ll >> 6; // This is divide by 64

      if (nextIndex != idx) {
        int consideredBits = lens[i] - ll & 0x3f;
        //Check for spill over only if all the bits are not considered
        if (consideredBits < lens[i]) {
          mask = (val >> (lens[i] - ll & 0x3f)); //& (0x7fffffffffffffffL >> (0x3f-pos));
          word = words[nextIndex];
          words[nextIndex] = (word | mask);
        }
      }

    }

    return words;
  }

  protected long[] get(int[] keys) {
    long[] words = new long[wSize];
    int ll = 0;
    int minLength = Math.min(lens.length, keys.length);
    for (int i = minLength - 1; i >= 0; i--) {

      long val = keys[i];

      int index = ll >> 6; // divide by 64 to get the new word index
      int pos = ll & 0x3f; // to ignore sign bit and consider the remaining
      val = val & (LONG_MAX >> (MAX_LENGTH - lens[i])); // To control the
      // logic so that
      // any val do not
      // exceed the
      // cardinality
      long mask = (val << pos);
      long word = words[index];
      words[index] = (word | mask);
      ll += lens[i];

      int nextIndex = ll >> 6; // This is divide by 64

      if (nextIndex != index) {
        int consideredBits = lens[i] - ll & 0x3f;
        //Check for spill over only if all the bits are not considered
        if (consideredBits < lens[i]) {
          // Check for spill over
          mask = (val >> (lens[i] - ll & 0x3f));
          word = words[nextIndex];
          words[nextIndex] = (word | mask);
        }
      }

    }

    return words;
  }

  private long[] getArray(long[] words) {
    long[] values = new long[lens.length];
    int ll = 0;
    for (int i = lens.length - 1; i >= 0; i--) {

      int index = ll >> 6;
      int pos = ll & 0x3f;
      long val = words[index];
      long mask = (LONG_MAX >>> (MAX_LENGTH - lens[i]));
      mask = mask << pos;
      values[i] = (val & mask);
      values[i] >>>= pos;
      ll += lens[i];

      int nextIndex = ll >> 6;
      if (nextIndex != index) {
        pos = ll & 0x3f;
        // Number of bits pending for current key is zero, no spill over
        if (pos != 0) {
          mask = (LONG_MAX >>> (MAX_LENGTH - pos));
          val = words[nextIndex];
          values[i] = values[i] | ((val & mask) << (lens[i] - pos));
        }
      }
    }
    return values;
  }

  public byte[] getBytes(long[] keys) {

    long[] words = get(keys);

    return getBytesVal(words);
  }

  private byte[] getBytesVal(long[] words) {
    int length = 8;
    byte[] bytes = new byte[byteSize];

    int l = byteSize - 1;
    for (int i = 0; i < words.length; i++) {
      long val = words[i];

      for (int j = length - 1; j > 0 && l > 0; j--) {
        bytes[l] = (byte) val;
        val >>>= 8;
        l--;
      }
      bytes[l] = (byte) val;
      l--;
    }
    return bytes;
  }

  public byte[] getBytes(int[] keys) {

    long[] words = get(keys);

    return getBytesVal(words);
  }

  public long[] getKeyArray(byte[] key, int offset) {

    int length = 8;
    int ls = byteSize;
    long[] words = new long[wSize];
    for (int i = 0; i < words.length; i++) {
      long l = 0;
      ls -= 8;
      int m = 0;
      if (ls < 0) {
        m = ls + length;
        ls = 0;
      } else {
        m = ls + 8;
      }
      for (int j = ls; j < m; j++) {
        l <<= 8;
        l ^= key[j + offset] & 0xFF;
      }
      words[i] = l;
    }

    return getArray(words);

  }

  public long[] getKeyArray(byte[] key, int[] maskByteRanges) {

    int length = 8;
    int ls = byteSize;
    long[] words = new long[wSize];
    for (int i = 0; i < words.length; i++) {
      long l = 0;
      ls -= 8;
      int m2 = 0;
      if (ls < 0) {
        m2 = ls + length;
        ls = 0;
      } else {
        m2 = ls + 8;
      }
      if (maskByteRanges == null) {
        for (int j = ls; j < m2; j++) {
          l <<= 8;
          l ^= key[j] & 0xFF;
        }
      } else {
        for (int j = ls; j < m2; j++) {
          l <<= 8;
          if (maskByteRanges[j] != -1) {
            l ^= key[maskByteRanges[j]] & 0xFF;
          }
        }
      }
      words[i] = l;
    }

    return getArray(words);

  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Bits) {
      Bits other = (Bits) obj;
      return Arrays.equals(lens, other.lens);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return Arrays.hashCode(lens);
  }
}
