
package org.exist.storage;

import org.w3c.dom.Node;
import org.exist.util.*;

/**
 *  Static methods to deal with the signature of a node stored
 *  in the first byte of the node data in the persistent dom.
 *  
 *  The bits in the signature are used as follows:
 *  
 *  <pre>
 *  8 4 2 1 8 4 2 1
 *  T T T N 0 0 I I
 *  </pre>
 *  
 *   where T = node type, N = has-namespace flag, I = no of bytes used to store
 *   the name of the node (local name for elements and attributes).
 */
public final class Signatures {
    
    public final static int Char = 0x0;
    public final static int Elem = 0x1;
	public final static int Proc = 0x2;
    public final static int Comm = 0x3;
    public final static int Attr = 0x4;
    public final static int Cdata = 0x5;
    
    public final static int IntContent = 0x1;
	public final static int ByteContent = 0x3;
    public final static int NoContent = 0x0;
    public final static int ShortContent = 0x2;
    
    /**
     *  Returns the storage size of the given type as
     *  number of bytes required.
     */
    public final static int getLength( int type ) {
        switch ( type ) {
            case IntContent:
                return 4;
            case ShortContent:
                return 2;
            case ByteContent:
                return 1;
        }
        return 0;
    }


    /**
     *  Returns one of IntContent, ShortContent, ByteContent
     *  or NoContent based on the number of bytes required
     *  to store the integer value given in length.
     */
    public final static byte getSizeType( int length ) {
        if ( length > Short.MAX_VALUE )
            return IntContent;
        else if ( length > Byte.MAX_VALUE )
            return ShortContent;
        else if ( length > 0 )
            return ByteContent;
        else
            return NoContent;
    }


    /**
     *  From the signature in byte 0 of the node data,
     *  extract the node type and return a constant
     *  as defined in {@link Node}.
     */
    public final static short getType( byte signature ) {
        byte type = (byte) ( ( signature & 0xE0 ) >> 0x5 );
        switch ( type ) {
            case Char:
                return Node.TEXT_NODE;
            case Elem:
                return Node.ELEMENT_NODE;
            case Attr:
                return Node.ATTRIBUTE_NODE;
            case Proc:
                return Node.PROCESSING_INSTRUCTION_NODE;
            case Comm:
                return Node.COMMENT_NODE;
            case Cdata:
                return Node.CDATA_SECTION_NODE;
        }
        System.err.println( "unknown node type" );
        return -1;
    }
    
    public final static int read( int type, byte[] data, int pos ) {
        switch ( type ) {
            case IntContent:
                return (int) ByteConversion.byteToInt( data, pos );
            case ShortContent:
                return (int) ByteConversion.byteToShort( data, pos );
            case ByteContent:
                return (int) data[pos];
        }
        return 0;
    }

    public final static void write( int type, int size, byte[] data, int pos ) {
        switch ( type ) {
            case IntContent:
                ByteConversion.intToByte( size, data, pos );
                break;
            case ShortContent:
                ByteConversion.shortToByte( (short) size, data, pos );
                break;
            case ByteContent:
                data[pos] = (byte) size;
                break;
        }
    }
}

