/*******************************************************************************
 * Copyright 2010 Cees De Groot, Alex Boisvert, Jan Kotek
 * 
 * Licensed 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 jdbm;

import java.io.IOException;

/**
 *  This class represents a page header. It is the common superclass for
 *  all different page views.
 */
class PageHeader implements BlockView {
    // offsets
    private static final short O_MAGIC = 0; // short magic
    private static final short O_NEXT = Magic.SZ_SHORT;  // long next
    private static final short O_PREV = O_NEXT + Magic.SZ_LONG; // long prev
    protected static final short SIZE = O_PREV + Magic.SZ_LONG;

    static final short PhysicalRowId_O_BLOCK = 0; // long block
    static final short PhysicalRowId_O_OFFSET = Magic.SZ_SIX_BYTE_LONG; // short offset
    static final int PhysicalRowId_SIZE = PhysicalRowId_O_OFFSET + Magic.SZ_SHORT;

    
    // my block
    protected BlockIo block;

    /**
     *  Constructs a PageHeader object from a block
     *
     *  @param block The block that contains the file header
     *  @throws IOException if the block is too short to keep the file
     *          header.
     */
    protected PageHeader(BlockIo block) {
        initialize(block);
        if (!magicOk())
            throw new Error("CRITICAL: page header magic for block "
                            + block.getBlockId() + " not OK "
                            + getMagic());
    }
    
    /**
     *  Constructs a new PageHeader of the indicated type. Used for newly
     *  created pages.
     */
    PageHeader(BlockIo block, short type) {
        initialize(block);
        setType(type);
    }
    
    /**
     *  Factory method to create or return a page header for the
     *  indicated block.
     */
    static PageHeader getView(BlockIo block) {
        BlockView view = block.getView();
        if (view != null && view instanceof PageHeader)
            return (PageHeader) view;
        else
            return new PageHeader(block);
    }
    
    private void initialize(BlockIo block) {
        this.block = block;
        block.setView(this);
    }
    
    /**
     *  Returns true if the magic corresponds with the fileHeader magic.
     */
    private boolean magicOk() {
        int magic = getMagic();
        return magic >= Magic.BLOCK
            && magic <= (Magic.BLOCK + Magic.FREEPHYSIDS_PAGE);
    }
    
    /**
     *  For paranoia mode
     */
    protected void paranoiaMagicOk() {
        if (!magicOk())
            throw new Error("CRITICAL: page header magic not OK "
                            + getMagic());
    }
    
    /** Returns the magic code */
    short getMagic() {
        return block.readShort(O_MAGIC);
    }

    /** Returns the next block. */
    long getNext() {
        paranoiaMagicOk();
        return block.readLong(O_NEXT);
    }
    
    /** Sets the next block. */
    void setNext(long next) {
        paranoiaMagicOk();
        block.writeLong(O_NEXT, next);
    }
    
    /** Returns the previous block. */
    long getPrev() {
        paranoiaMagicOk();
        return block.readLong(O_PREV);
    }
    
    /** Sets the previous block. */
    void setPrev(long prev) {
        paranoiaMagicOk();
        block.writeLong(O_PREV, prev);
    }
    
    /** Sets the type of the page header */
    void setType(short type) {
        block.writeShort(O_MAGIC, (short) (Magic.BLOCK + type));
    }
    
    /** Returns the block number */
    long getLocationBlock(short pos) {
        return block.readSixByteLong(pos + PhysicalRowId_O_BLOCK);
    }
    
    /** Sets the block number */
    void setLocationBlock(short pos,long value) {
        block.writeSixByteLong(pos + PhysicalRowId_O_BLOCK, value);
    }
    
    /** Returns the offset */
    short getLocationOffset(short pos) {
        return block.readShort(pos + PhysicalRowId_O_OFFSET);
    }
    
    /** Sets the offset */
    void setLocationOffset(short pos,short value) {
        block.writeShort(pos + PhysicalRowId_O_OFFSET, value);
    }


}

@@ -1102,22 +1102,8 @@
 ORT;
-  // long next
 %0A   
@@ -1161,26 +1161,22 @@
 .SZ_
-LONG; // long prev
+SIX_BYTE_LONG;
 %0A   
@@ -1230,16 +1230,25 @@
 agic.SZ_
+SIX_BYTE_
 LONG;%0A%0A 
@@ -3426,24 +3426,31 @@
 n block.read
+SixByte
 Long(O_NEXT)
@@ -3447,24 +3447,24 @@
 ng(O_NEXT);%0A
-
     %7D%0A    %0A 
@@ -3566,24 +3566,31 @@
  block.write
+SixByte
 Long(O_NEXT,
@@ -3720,16 +3720,23 @@
 ock.read
+SixByte
 Long(O_P
@@ -3837,32 +3837,32 @@
 anoiaMagicOk();%0A
-
         block.wr
@@ -3864,16 +3864,23 @@
 ck.write
+SixByte
 Long(O_P

make PageHeader to use 16 bytes instead of 20 bytes