/*
 * 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;
  /**
   * wsize.
   */
  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[] vals = 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;
      vals[i] = (val & mask);
      vals[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];
          vals[i] = vals[i] | ((val & mask) << (lens[i] - pos));
        }
      }
    }
    return vals;
  }

  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);
  }
}
