/*
 * 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.hadoop.hbase.codec.prefixtree.decode.column;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.codec.prefixtree.PrefixTreeBlockMeta;
import org.apache.hadoop.hbase.codec.prefixtree.encode.other.ColumnNodeType;

/**
 * Position one of these appropriately in the data block and you can call its methods to retrieve
 * the family or qualifier at the current position.
 */
@InterfaceAudience.Private
public class ColumnReader {

  /****************** fields *************************/

  protected PrefixTreeBlockMeta blockMeta;

  protected byte[] columnBuffer;
  protected int columnOffset;
  protected int columnLength;
  protected ColumnNodeType nodeType;  

  protected ColumnNodeReader columnNodeReader;


  /******************** construct *******************/

  public ColumnReader(byte[] columnBuffer, ColumnNodeType nodeType) {
    this.columnBuffer = columnBuffer;
    this.nodeType = nodeType;
    this.columnNodeReader = new ColumnNodeReader(columnBuffer, nodeType);
  }

  public void initOnBlock(PrefixTreeBlockMeta blockMeta, byte[] block) {
    this.blockMeta = blockMeta;
    clearColumnBuffer();
    columnNodeReader.initOnBlock(blockMeta, block);
  }


  /********************* methods *******************/

  public ColumnReader populateBuffer(int offsetIntoColumnData) {
    clearColumnBuffer();
    int nextRelativeOffset = offsetIntoColumnData;
    while (true) {
      int absoluteOffset = 0;
      if (nodeType == ColumnNodeType.FAMILY) {
        absoluteOffset = blockMeta.getAbsoluteFamilyOffset() + nextRelativeOffset;
      } else if (nodeType == ColumnNodeType.QUALIFIER) {
        absoluteOffset = blockMeta.getAbsoluteQualifierOffset() + nextRelativeOffset;
      } else {
        absoluteOffset = blockMeta.getAbsoluteTagsOffset() + nextRelativeOffset;
      }
      columnNodeReader.positionAt(absoluteOffset);
      columnOffset -= columnNodeReader.getTokenLength();
      columnLength += columnNodeReader.getTokenLength();
      columnNodeReader.prependTokenToBuffer(columnOffset);
      if (columnNodeReader.isRoot()) {
        return this;
      }
      nextRelativeOffset = columnNodeReader.getParentStartPosition();
    }
  }

  public byte[] copyBufferToNewArray() {// for testing
    byte[] out = new byte[columnLength];
    System.arraycopy(columnBuffer, columnOffset, out, 0, out.length);
    return out;
  }

  public int getColumnLength() {
    return columnLength;
  }

  public void clearColumnBuffer() {
    columnOffset = columnBuffer.length;
    columnLength = 0;
  }


  /****************************** get/set *************************************/

  public int getColumnOffset() {
    return columnOffset;
  }

}

