/**
 *  Copyright 2005-2016 Red Hat, Inc.
 *
 *  Red Hat 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 io.fabric8.gateway.handlers.detecting.protocol.openwire.codec;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;

public final class BooleanStream {

    byte data[] = new byte[48];
    short arrayLimit;
    short arrayPos;
    byte bytePos;

    public boolean readBoolean() throws IOException {
        assert arrayPos <= arrayLimit;
        byte b = data[arrayPos];
        boolean rc = ((b >> bytePos) & 0x01) != 0;
        bytePos++;
        if (bytePos >= 8) {
            bytePos = 0;
            arrayPos++;
        }
        return rc;
    }

    public void writeBoolean(boolean value) throws IOException {
        if (bytePos == 0) {
            arrayLimit++;
            if (arrayLimit >= data.length) {
                // re-grow the array.
                byte d[] = new byte[data.length * 2];
                System.arraycopy(data, 0, d, 0, data.length);
                data = d;
            }
        }
        if (value) {
            data[arrayPos] |= 0x01 << bytePos;
        }
        bytePos++;
        if (bytePos >= 8) {
            bytePos = 0;
            arrayPos++;
        }
    }

    public void marshal(DataOutput dataOut) throws IOException {
        if (arrayLimit < 64) {
            dataOut.writeByte(arrayLimit);
        } else if (arrayLimit < 256) { // max value of unsigned byte
            dataOut.writeByte(0xC0);
            dataOut.writeByte(arrayLimit);
        } else {
            dataOut.writeByte(0x80);
            dataOut.writeShort(arrayLimit);
        }

        dataOut.write(data, 0, arrayLimit);
        clear();
    }

    public void marshal(ByteBuffer dataOut) {
        if (arrayLimit < 64) {
            dataOut.put((byte)arrayLimit);
        } else if (arrayLimit < 256) { // max value of unsigned byte
            dataOut.put((byte)0xC0);
            dataOut.put((byte)arrayLimit);
        } else {
            dataOut.put((byte)0x80);
            dataOut.putShort(arrayLimit);
        }

        dataOut.put(data, 0, arrayLimit);
    }

    public void unmarshal(DataInput dataIn) throws IOException {

        arrayLimit = (short)(dataIn.readByte() & 0xFF);
        if (arrayLimit == 0xC0) {
            arrayLimit = (short)(dataIn.readByte() & 0xFF);
        } else if (arrayLimit == 0x80) {
            arrayLimit = dataIn.readShort();
        }
        if (data.length < arrayLimit) {
            data = new byte[arrayLimit];
        }
        dataIn.readFully(data, 0, arrayLimit);
        clear();
    }

    public void clear() {
        arrayPos = 0;
        bytePos = 0;
    }

    public int marshalledSize() {
        if (arrayLimit < 64) {
            return 1 + arrayLimit;
        } else if (arrayLimit < 256) {
            return 2 + arrayLimit;
        } else {
            return 3 + arrayLimit;
        }
    }

}
