/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.jlab.hipo.data;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.jlab.hipo.io.HipoByteUtils;

/**
 *
 * @author gavalian
 */
public class HipoNode {
    
    ByteBuffer   nodeBuffer   = null;
    HipoNodeType nodeType     = null;
    
    /**
     * Description of header bytes order.
     */
    private int            headerLength = 8;
    private int  headerLengthDataOffset = 6;
    private int     hederTypeDataOffset = 2;
       
    
    public HipoNode(int group, int item, HipoNodeType type, int length){
        createNode(group, item, type, length);
    }
    
    public HipoNode(int group, int item, String value){
        createNode(group,item,value);
    }
        
    public HipoNode(int group, int item, float[] value){
        createNode(group,item,HipoNodeType.FLOAT,value.length);
        for(int i = 0; i < value.length;i++) this.setFloat(i, value[i]);        
    }
    
    public HipoNode(int group, int item, double[] value){
        createNode(group,item,HipoNodeType.DOUBLE,value.length);
        for(int i = 0; i < value.length;i++) this.setDouble(i, value[i]);        
    }
    /**
     * Initialize HipoNode from a byte array. 
     * @param buffer byte array with the data
     */
    public HipoNode(byte[] buffer){
        nodeBuffer = ByteBuffer.wrap(buffer);
        nodeBuffer.order(ByteOrder.LITTLE_ENDIAN);
        nodeType = getType();
    }
    
    public final void createNode(int group, int item, String value){
        byte[] array = value.getBytes();
        createNode(group,item,HipoNodeType.STRING,array.length);
        System.arraycopy(array, 0, nodeBuffer.array(), 8, array.length);
        //for(int i = 0; i < array.length; i++) { setByte(i,array[i]);}
    }
    /**
     * Creates a node for given type
     * @param group group id
     * @param item item id
     * @param type type of the node
     * @param length number of elements in the node
     */
    public final void createNode(int group, int item, HipoNodeType type, int length){
        int bytesPerEntry = type.getSize(); 
        int totalLength = this.headerLength + length*bytesPerEntry;
        byte[] array = new byte[totalLength];
        nodeBuffer   = ByteBuffer.wrap(array);
        nodeBuffer.order(ByteOrder.LITTLE_ENDIAN);
        
        short groupID  = HipoByteUtils.getShortFromInt(group);
        int   lengthID = length*bytesPerEntry;
        byte  itemID   = HipoByteUtils.getByteFromInt(item);
        byte  typeID   = HipoByteUtils.getByteFromInt(type.getType());
        
        nodeBuffer.putShort( 0,  groupID); // byte 0 and 1 (16 bits) are group ID
        nodeBuffer.put(      2,   itemID); // byte 2 ( 8 bits) is item id
        nodeBuffer.put(      3,   typeID); // byte 3 describes the type 
        nodeBuffer.putInt(   4, lengthID);
        
        nodeType = getType();
    }
    /**
     * returns number of elements in the data array. This is not the buffer length.
     * @return n elements of the array if the node is a primitive data.
     */
    public int getDataSize(){
        HipoNodeType   type = getType();
        int    bufferLength = nodeBuffer.getInt(4);
        int           ndata = bufferLength/type.getSize();
        return ndata;
    }
    /**
     * returns the size of the buffer, including the header.
     * @return internal ByteBuffer size
     */
    public int getBufferSize(){
        return nodeBuffer.capacity();
    }
    /**
     * returns the byte[] array of the buffer 
     * @return array of bytes
     */
    public byte[] getBufferData(){
        return nodeBuffer.array();
    }
    /**
     * returns the group id of the node.
     * @return group id
     */
    public int getGroup(){
        short groupid = nodeBuffer.getShort(0);
        return (int) groupid;
    }
    /**
     * returns the item id of the node
     * @return item id
     */
    public int getItem(){
        byte itemid = nodeBuffer.get(2);
        return (int) itemid;
    }
    
    /**
     * returns string representation of the data.
     * @return data string
     */
    public String getDataString(){
        StringBuilder str = new StringBuilder();
        HipoNodeType  type = getType();
        
        if(type==HipoNodeType.BYTE){
            int ndata = getDataSize();
            for(int i = 0; i < ndata; i++){
                str.append(String.format(" %8d", getByte(i)));
            }
        }
        
        if(type==HipoNodeType.SHORT){
            int ndata = getDataSize();
            for(int i = 0; i < ndata; i++){
                str.append(String.format(" %8d", getShort(i)));
            }
        }
        
        if(type==HipoNodeType.INT){
            int ndata = getDataSize();
            for(int i = 0; i < ndata; i++){
                str.append(String.format(" %8d", getInt(i)));
            }
        }
        if(type==HipoNodeType.LONG){
            int ndata = getDataSize();
            for(int i = 0; i < ndata; i++){
                str.append(String.format(" %8d", getLong(i)));
            }
        }
        if(type==HipoNodeType.FLOAT){
            int ndata = getDataSize();
            for(int i = 0; i < ndata; i++){
                str.append(String.format(" %8.3f", getFloat(i)));
            }
        }
        
        if(type==HipoNodeType.DOUBLE){
            int ndata = getDataSize();
            for(int i = 0; i < ndata; i++){
                str.append(String.format(" %8.3f", getDouble(i)));
            }
        }
        
        if(type==HipoNodeType.VECTOR3F){
            int ndata = getDataSize();
            for(int i = 0; i < ndata; i++){
                str.append(String.format("(%.3f,%.3f,%.3f) ", getVectorX(i),getVectorY(i),getVectorZ(i)));
            }
        }
        return str.toString();
    }    
    /**
     * returns a String with header information.
     * @return string representation of the header.
     */
    public String getHeaderString(){
        StringBuilder str = new StringBuilder();
        short group = nodeBuffer.getShort(0);
        byte  item  = nodeBuffer.get(2);
        byte  type  = nodeBuffer.get(3);
        int   len   = nodeBuffer.getInt(4);
        str.append(String.format("(%8d,%4d) <%2d> [%6d]", group,item,type,len));
        return str.toString();
    }
    /**
     * returns type of the elements stored in the buffer.
     * @return 
     */
    public final HipoNodeType  getType(){
        int type = (int) nodeBuffer.get(3);
        return HipoNodeType.getType(type);
    }    
    /**
     * returns offset of the data element in the ByteBuffer.
     * includes the header length and size of element type.
     * @param index index if the element.
     * @return 
     */
    private int getOffset(int index){
        HipoNodeType type = getType();
        return this.headerLength + type.getSize()*index;
    }    
    /**
     * returns a String object from the node. Strings are stored 
     * as byte[]. The data is copied into String.
     * @return String representation of byte array.
     */
    public String getString(){
        if(nodeType!=HipoNodeType.STRING){
            printWrongTypeMessage(HipoNodeType.STRING);
            return "";
        }
        int offset = getOffset(0);
        int length = getDataSize();
        byte[] array = new byte[length];
        System.arraycopy(nodeBuffer.array(), offset, array, 0, length);
        return new String(array);
    }
    
    /**
     * returns a byte element from the array.
     * @param index index of the element
     * @return 
     */
    public byte getByte(int index){
        if(nodeType!=HipoNodeType.BYTE){
            printWrongTypeMessage(HipoNodeType.BYTE);
            return (byte) 0;
        }
        int offset = getOffset(index);
        return nodeBuffer.get(offset);
    }
    
    public byte[] getByte(){
        byte[] array = new byte[this.getDataSize()];
        System.arraycopy(this.nodeBuffer.array(), headerLength, array, 0, array.length);
        return array;
    }
    /**
     * returns a float array containing the data from the node.
     * needs to be optimized with ArrayCopy !
     * @return float[] array of the node.
     */
    public float[] getFloat(){
        if(nodeType!=HipoNodeType.FLOAT){
            printWrongTypeMessage(HipoNodeType.FLOAT);
            return new float[0];
        }
        float[] result = new float[this.getDataSize()];
        for(int i = 0; i < result.length; i++) result[i] = getFloat(i);
        return result;
    }
    /**
     * returns a float array containing the data from the node.
     * needs to be optimized with ArrayCopy !
     * @return float[] array of the node.
     */
    public double[] getDouble(){
        if(nodeType!=HipoNodeType.DOUBLE){
            printWrongTypeMessage(HipoNodeType.DOUBLE);
            return new double[0];
        }
        double[] result = new double[this.getDataSize()];
        for(int i = 0; i < result.length; i++) result[i] = getDouble(i);
        return result;
    }
    /**
     * returns a float number of the element with given index
     * @param index index of the element.
     * @return 
     */
    public float getFloat(int index){
        if(nodeType!=HipoNodeType.FLOAT){
            printWrongTypeMessage(HipoNodeType.FLOAT);
            return 0.0f;
        }
        int offset = getOffset(index);
        return nodeBuffer.getFloat(offset);
    }
    /*
    public short[] getDataShort(){
        
    }*/
    /**
     * Get X component of the vector from the node with TYPE VECTOR3F
     * @param index index of the vector
     * @return X component
     */
    public float getVectorX(int index){
        if(nodeType!=HipoNodeType.VECTOR3F){
            printWrongTypeMessage(HipoNodeType.VECTOR3F);
            return (float) 0;
        }
        int start  = getOffset(0);
        int offset = start + (index*nodeType.getSize());
        return nodeBuffer.getFloat(offset);
    }
    /**
     * Get Y component of the vector from the node with TYPE VECTOR3F
     * @param index index of the vector
     * @return Y component
     */    
    public float getVectorY(int index){
        if(nodeType!=HipoNodeType.VECTOR3F){
            printWrongTypeMessage(HipoNodeType.VECTOR3F);
            return (float) 0;
        }
        int start  = getOffset(0);
        int offset = start + (index*nodeType.getSize()+4);
        return nodeBuffer.getFloat(offset);
    }
    /**
     * Get Z component of the vector from the node with TYPE VECTOR3F
     * @param index index of the vector
     * @return Z component
     */    
    public float getVectorZ(int index){
        if(nodeType!=HipoNodeType.VECTOR3F){
            printWrongTypeMessage(HipoNodeType.VECTOR3F);
            return (float) 0;
        }
        int start  = getOffset(0);
        int offset = start + (index*nodeType.getSize()+8);
        return nodeBuffer.getFloat(offset);
    }
    /**
     * returns the value of the short array for given index.
     * @param index index of the array
     * @return the value
     */
    public short getShort(int index){
        if(nodeType!=HipoNodeType.SHORT){
            printWrongTypeMessage(HipoNodeType.SHORT);
            return (short) 0;
        }
        int offset = getOffset(index);
        return nodeBuffer.getShort(offset);
    }
    
    public int getInt(int index){
        if(nodeType!=HipoNodeType.BYTE&&nodeType!=HipoNodeType.SHORT&&
                nodeType!=HipoNodeType.INT){
            printWrongTypeMessage(HipoNodeType.INT);
            return 0;
        }

        int offset = getOffset(index);
        
        if(nodeType==HipoNodeType.INT){
            return nodeBuffer.getInt(offset);
        }
        
        if(nodeType==HipoNodeType.SHORT){
            return (int) nodeBuffer.getShort(offset);
        }
        
        if(nodeType==HipoNodeType.BYTE){
            return (int) nodeBuffer.get(offset);
        }
        
        return 0;        
    }
    
    public int[] getInt(){
        if(this.nodeType!=HipoNodeType.INT){
            this.printWrongTypeMessage(HipoNodeType.INT);
            return new int[0];
        }

        int[] array = new int[this.getDataSize()];
        for(int i = 0; i < array.length; i++) array[i] = this.getInt(i);
        //System.arraycopy(this.nodeBuffer.array(), headerLength, array, 0, array.length*4);
        return array;
    }
    
    public short[] getShort(){
        if(this.nodeType!=HipoNodeType.SHORT){
            this.printWrongTypeMessage(HipoNodeType.SHORT);
            return new short[0];
        }
        
        short[] array = new short[this.getDataSize()];
        for(int i = 0; i < array.length; i++) array[i] = this.getShort(i);
        /*System.out.println(" copying " + headerLength +  "  " + (array.length*2) +
                "   " + this.nodeBuffer.array().length);
        System.arraycopy(this.nodeBuffer.array(), headerLength, array, 0, array.length);*/
        return array;
    }
    
    public long getLong(int index){
        if(nodeType!=HipoNodeType.LONG){
            printWrongTypeMessage(HipoNodeType.LONG);
            return 0;
        }
        int offset = getOffset(index);
        return nodeBuffer.getLong(offset);
    }
    
    public double getDouble(int index){
        if(nodeType!=HipoNodeType.DOUBLE){
            printWrongTypeMessage(HipoNodeType.DOUBLE);
            return 0.0;
        }
        int offset = getOffset(index);
        return nodeBuffer.getDouble(offset);
    }
    /**
     * Set content of the node with type BYTE, for element index
     * @param index element index
     * @param value byte value to set
     */
    public void setByte(int index, byte value){                
        if(nodeType!=HipoNodeType.BYTE){
            printWrongTypeMessage(HipoNodeType.BYTE);
            return;
        }
        int offset = getOffset(index);
        nodeBuffer.put(offset, value);
    }
    
    public void setShort(int index, short value){
        if(nodeType!=HipoNodeType.SHORT){
            printWrongTypeMessage(HipoNodeType.SHORT);
            return;
        }
        int offset = getOffset(index);
        nodeBuffer.putShort(offset, value);
    }        
    /**
     * set integer value to the element of the node
     * @param index order of the array
     * @param value value to set
     */
    public void setInt(int index, int value){

        if(nodeType==HipoNodeType.INT){
            int offset = getOffset(index);
            nodeBuffer.putInt(offset, value);
            return;
        }
        
        if(nodeType==HipoNodeType.SHORT){
            if(value>Short.MIN_VALUE&&value setting int value to short failed. Value is "
                + " out of range. " + value);
                return;
            }
        }
        
        if(nodeType==HipoNodeType.BYTE){
            if(value>Byte.MIN_VALUE&&value setting int value to short failed. Value is "
                + " out of range. " + value);
                return;
            }
        }
        
        printWrongTypeMessage(HipoNodeType.INT);
         
        /*if(nodeType!=HipoNodeType.INT){
            printWrongTypeMessage(HipoNodeType.INT);
            return;
        }*/
        //int offset = getOffset(index);
        //nodeBuffer.putInt(offset, value);
    } 
    
    public void setLong(int index, long value){
        if(nodeType!=HipoNodeType.LONG){
            printWrongTypeMessage(HipoNodeType.LONG);
            return;
        }
        int offset = getOffset(index);
        nodeBuffer.putLong(offset, value);
    }
    
    public void setFloat(int index, float value){
        if(nodeType!=HipoNodeType.FLOAT){
            printWrongTypeMessage(HipoNodeType.FLOAT);
            return;
        }
        int offset = getOffset(index);
        nodeBuffer.putFloat(offset, value);
    }
    
    public void setDouble(int index, double value){
        if(nodeType!=HipoNodeType.DOUBLE){
            printWrongTypeMessage(HipoNodeType.DOUBLE);
            return;
        }
        int offset = getOffset(index);
        nodeBuffer.putDouble(offset, value);
    }
    /**
     * sets all components for the vector with index
     * @param index order of the vector
     * @param x x-component of the vector
     * @param y y-component of the vector
     * @param z z-component of the vector
     */
    public void setVector(int index, float x, float y, float z){
        setVectorX(index,x); setVectorY(index,y); setVectorZ(index,z);        
    }
    /**
     * sets X component of the vector with index
     * @param index index of the vector
     * @param value X component value to set
     */
    public void setVectorX(int index, float value){
        if(nodeType!=HipoNodeType.VECTOR3F){
            printWrongTypeMessage(HipoNodeType.VECTOR3F);
            return;
        }
        int start  = getOffset(0);
        int offset = start + (index*nodeType.getSize());
        nodeBuffer.putFloat(offset,value);
    }
   /**
     * sets X component of the vector with index
     * @param index index of the vector
     * @param value X component value to set
     */
    public void setVectorY(int index, float value){
        if(nodeType!=HipoNodeType.VECTOR3F){
            printWrongTypeMessage(HipoNodeType.VECTOR3F);
            return;
        }
        int start  = getOffset(0);
        int offset = start + (index*nodeType.getSize()+4);
        nodeBuffer.putFloat(offset,value);
    }
   /**
     * sets X component of the vector with index
     * @param index index of the vector
     * @param value X component value to set
     */
    public void setVectorZ(int index, float value){
        if(nodeType!=HipoNodeType.VECTOR3F){
            printWrongTypeMessage(HipoNodeType.VECTOR3F);
            return;
        }
        int start  = getOffset(0);
        int offset = start + (index*nodeType.getSize()+8);
        nodeBuffer.putFloat(offset,value);
    }    
    /**
     * prints error message when wrong type is selected for the node.
     * @param type mistaken type
     */
    private void printWrongTypeMessage(HipoNodeType type){
        System.out.print("[hipo node] --> error : ");
        System.out.print(String.format("(%d,%d)", getGroup(), getItem()));
        System.out.println(" requested type="+type.getName()+" has type="+nodeType.getName());
    }
    /**
     * main program for tests
     * @param args 
     */
    public static void main(String[] args){
        /*
        HipoNode node = new HipoNode(1200,1,HipoNodeType.SHORT,5);
        
        for(int i = 0; i < 5; i++) { node.setShort(i, (short) ((i+1)*2) );}
        System.out.println(node.getHeaderString() + " : " + node.getDataString());
        
        HipoNode nodeF = new HipoNode(1200,1,HipoNodeType.FLOAT,8);
        for(int i = 0; i < 8; i++) { nodeF.setFloat(i,  (float)  ((i+1)*2.0+0.5) );}
        System.out.println(nodeF.getHeaderString() + " : " + nodeF.getDataString());
        
        HipoNode nodeString = new HipoNode(20,1,"Histogram");
        
        System.out.println("VALUE = [" + nodeString.getString() + "]");
        */
        /*
        HipoNode node = new HipoNode(300,1,HipoNodeType.VECTOR3F,8);
        for(int i = 0; i < node.getDataSize(); i++){
            node.setVector(i, (float) Math.random(),(float) Math.random(), (float) Math.random());            
        }
        System.out.println("DATA SIZE = " + node.getDataSize());
        System.out.println(node.getDataString());
        */
        
        HipoNode node = new HipoNode(300,1,HipoNodeType.SHORT,20);
        for(int i = 0; i < 20; i++){
            int value = (i+1)*20;
            node.setInt(i, value);
        }

        System.out.println(node.getDataString());
        
        short[] buff = node.getShort();
        for(int i = 0; i < buff.length ; i++){
            System.out.println( i + " = " + buff[i]);
        }

        HipoNode nodeB = new HipoNode(300,1,HipoNodeType.BYTE,20);
        for(int i = 0; i < 20; i++){
            int value = (i+1)*2;
            nodeB.setByte(i, (byte) value);
        }
        byte[] buffb = nodeB.getByte();
        for(int i = 0; i < buffb.length ; i++){
            System.out.println( i + " = " + buffb[i]);
        }
    }
}

 

Ads help maintain this website.