/*
 * 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.jena.dboe.base.recordbuffer;

import java.nio.ByteBuffer;

import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.dboe.base.block.Block;
import org.apache.jena.dboe.base.buffer.RecordBuffer;
import org.apache.jena.dboe.base.page.PageBase;
import org.apache.jena.dboe.base.record.RecordFactory;
import org.apache.jena.dboe.sys.Sys;

/**
 * The on-disk form of a block of a single RecordBuffer
 * (i.e. this is not part of a BTree/BPlusTree branch node).
 * This must be compatible with B+Tree records nodes and hashbuckets.
 */

public abstract class RecordBufferPageBase extends PageBase // implements Page
{
    // Field offsets
    final public static int     COUNT        = 0;
    // Length due to this class - subclasses may use more overhead.
    final private static int    FIELD_LENGTH = Sys.SizeOfInt;

    protected final int         headerLength;

    // Interface: "Page" - id, byteBuffer, count
    protected RecordBuffer      recBuff;
    private final RecordFactory factory;

    // private int offset; // Bytes of overhead.

    public static int calcRecordSize(RecordFactory factory, int blkSize, int headerOffset) {
        // Length = X*recordLength + HEADER
        int x = blkSize - totalOffset(headerOffset);
        return x / factory.recordLength();
    }

    public static int calcBlockSize(RecordFactory factory, int maxRec, int headerOffset) {
        return totalOffset(headerOffset) + factory.recordLength() * maxRec;
    }

    private static int totalOffset(int headerOffset) {
        return FIELD_LENGTH + headerOffset;
    }

    protected RecordBufferPageBase(Block block, int offset, RecordFactory factory, int count) {
        // This code knows the alignment of the records in the ByteBuffer.
        super(block);
        this.headerLength = FIELD_LENGTH + offset; // NB +4 for the count field
        this.factory = factory;
        rebuild(block, count);
    }

    protected void rebuild(Block block, int count) {
        ByteBuffer bb = block.getByteBuffer();
        bb.clear();
        bb.position(headerLength);
        bb = bb.slice();
        this.recBuff = new RecordBuffer(bb, factory, count);
    }

    public final RecordBuffer getRecordBuffer() {
        return recBuff;
    }

    public final int getCount() {
        return recBuff.size();
    }

    public final int getMaxSize() {
        return recBuff.maxSize();
    }

    public void setCount(int count) {
        recBuff.setSize(count);
    }

    @Override
    public String toString() {
        return String.format("RecordBufferPageBase[id=%d]: %s", getBackingBlock().getId(), recBuff);
    }

    @Override
    public void output(IndentedWriter out) {
        out.print(toString());
    }
}
