/*
 * @(#)BigEndianBits.java
 *
 * Copyright (c) 2002-2003 JSCAPE
 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JSCAPE. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 * the terms of the license agreement you entered into with JSCAPE.
 */

package com.jscape.util;

/**
 * Utility methods for packing/unpacking primitive values in/out of byte arrays using big-endian byte ordering.
 *
 * @author Alex
 */
public class BigEndianBits
        implements EndianBits {

    public static final EndianBits INSTANCE = new BigEndianBits();

    /**
     * Returns boolean value stored in byte form.
     *
     * @param buffer data
     * @param off    data offset
     *
     * @return value
     */
    public boolean getBoolean(byte[] buffer, int off) {
        return (buffer[off] != 0);
    }

    /**
     * Returns char value stored in byte form.
     *
     * @param buffer data
     * @param off    data offset
     *
     * @return value
     */
    public char getChar(byte[] buffer, int off) {
        char value = (char) ((buffer[off] & 0xFF) << 8);
        value |= (buffer[off + 1] & 0xFF);

        return value;
    }

    /**
     * Returns short value stored in byte form.
     *
     * @param buffer data
     * @param off    data offset
     *
     * @return value
     */
    public short getShort(byte[] buffer, int off) {
        short value = (short) ((buffer[off] & 0xFF) << 8);
        value |= (buffer[off + 1] & 0xFF);

        return value;
    }

    /**
     * Returns integer value stored in byte form.
     *
     * @param buffer data
     * @param off    data offset
     *
     * @return value
     */
    public int getInt(byte[] buffer, int off) {
        int value = (buffer[off] & 0xFF) << 24;
        value |= (buffer[off + 1] & 0xFF) << 16;
        value |= (buffer[off + 2] & 0xFF) << 8;
        value |= buffer[off + 3] & 0xFF;

        return value;
    }

    /**
     * Returns long value stored in byte form.
     *
     * @param buffer data
     * @param off    data offset
     *
     * @return value
     */
    public long getLong(byte[] buffer, int off) {
        long value = (buffer[off] & 0xFFL) << 56;
        value |= (buffer[off + 1] & 0xFFL) << 48;
        value |= (buffer[off + 2] & 0xFFL) << 40;
        value |= (buffer[off + 3] & 0xFFL) << 32;
        value |= (buffer[off + 4] & 0xFFL) << 24;
        value |= (buffer[off + 5] & 0xFFL) << 16;
        value |= (buffer[off + 6] & 0xFFL) << 8;
        value |= buffer[off + 7] & 0xFFL;

        return value;
    }

    /**
     * Returns float value stored in byte form.
     *
     * @param buffer data
     * @param off    data offset
     *
     * @return value
     */
    public float getFloat(byte[] buffer, int off) {
        return Float.intBitsToFloat(getInt(buffer, off));
    }

    /**
     * Returns double value stored in byte form.
     *
     * @param buffer data
     * @param off    data offset
     *
     * @return value
     */
    public double getDouble(byte[] buffer, int off) {
        return Double.longBitsToDouble(getLong(buffer, off));
    }

    /**
     * Puts boolean value in byte form.
     *
     * @param value  value
     * @param buffer data
     * @param off    data offset
     */
    public byte[] putBoolean(boolean value, byte[] buffer, int off) {
        buffer[off] = (byte) (value ? 1 : 0);
        return buffer;
    }

    /**
     * Puts char value in byte form.
     *
     * @param value  value
     * @param buffer data
     * @param off    data offset
     */
    public byte[] putChar(char value, byte[] buffer, int off) {
        buffer[off] = (byte) (value >>> 8);
        buffer[off + 1] = (byte) (value);
        return buffer;
    }

    /**
     * Puts short value in byte form.
     *
     * @param value  value
     * @param buffer data
     * @param off    data offset
     */
    public byte[] putShort(short value, byte[] buffer, int off) {
        buffer[off] = (byte) (value >>> 8);
        buffer[off + 1] = (byte) (value);
        return buffer;
    }

    /**
     * Puts integer value in byte form.
     *
     * @param value  value
     * @param buffer data
     * @param off    data offset
     */
    public byte[] putInt(int value, byte[] buffer, int off) {
        buffer[off] = (byte) (value >>> 24);
        buffer[off + 1] = (byte) (value >>> 16);
        buffer[off + 2] = (byte) (value >>> 8);
        buffer[off + 3] = (byte) (value);
        return buffer;
    }

    /**
     * Puts long value in byte form.
     *
     * @param value  value
     * @param buffer data
     * @param off    data offset
     */
    public byte[] putLong(long value, byte[] buffer, int off) {
        buffer[off] = (byte) (value >>> 56);
        buffer[off + 1] = (byte) (value >>> 48);
        buffer[off + 2] = (byte) (value >>> 40);
        buffer[off + 3] = (byte) (value >>> 32);
        buffer[off + 4] = (byte) (value >>> 24);
        buffer[off + 5] = (byte) (value >>> 16);
        buffer[off + 6] = (byte) (value >>> 8);
        buffer[off + 7] = (byte) (value);

        return buffer;
    }

    /**
     * Puts float value in byte form.
     *
     * @param value  value
     * @param buffer data
     * @param off    data offset
     */
    public byte[] putFloat(float value, byte[] buffer, int off) {
        return putInt(Float.floatToIntBits(value), buffer, off);
    }

    /**
     * Puts double value in byte form.
     *
     * @param value  value
     * @param buffer data
     * @param off    data offset
     */
    public byte[] putDouble(double value, byte[] buffer, int off) {
        return putLong(Double.doubleToLongBits(value), buffer, off);
    }

}
