/*
 * @(#)Buffer.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;

import java.nio.charset.Charset;

/**
 * @author Alex
 */
public class Buffer {

    private byte[] buffer;
    private int index;

    public Buffer(int capacity) {
        this.buffer = new byte[capacity];
        this.index = 0;
    }

    public byte[] getBuffer() {
        return this.buffer;
    }

    public int getLength() {
        return this.index;
    }

    public int getCapacity() {
        return this.buffer.length;
    }

    public void setLength(int value) {
        if (this.buffer.length < value) {
            allocate(value - this.index);
        }

        this.index = value;
    }

    public int available() {
        return (this.buffer.length - this.index);
    }

    public void allocate(int size) {
        if (available() > size) {
            return;
        }

        int needed = size - available();
        byte[] tmp = new byte[(int) ((this.buffer.length + needed) * 1.5)];
        System.arraycopy(this.buffer, 0, tmp, 0, this.index);
        this.buffer = tmp;
    }

    public void append(byte data) {
        allocate(1);
        this.buffer[this.index] = data;
        ++this.index;
    }

    public void append(byte[] data, int off, int len) {
        allocate(len);
        System.arraycopy(data, off, this.buffer, this.index, len);
        this.index += len;
    }

    public void append(byte[] data) {
        append(data, 0, data.length);
    }

    public void insert(int index, byte[] data, int off, int len) {
        int dataEndIndex = index + len;
        int movedDataLength = this.index - index;
        int totalDataLength = len + movedDataLength;
        allocate((index + totalDataLength) - this.index);

        System.arraycopy(this.buffer, index, this.buffer, dataEndIndex, movedDataLength);
        System.arraycopy(data, off, this.buffer, index, len);
    }

    public byte get(int index) {
        return this.buffer[index];
    }

    public void set(byte data, int index) {
        if (index < this.index) {
            this.buffer[index] = data;
        } else {
            append(data);
        }
    }

    public void set(byte[] buf, int offset, int len, int index) {
        int needed = len - (this.index - index);
        if (needed > 0) {
            allocate(needed);
        }
        System.arraycopy(buf, offset, this.buffer, index, len);

        this.index = index + len;
    }

    public boolean startsWith(byte[] data) {
        if (getLength() < data.length) {
            return false;
        }

        for (int i = 0; i < data.length; ++i) {
            if (data[i] != get(i)) {
                return false;
            }
        }

        return true;
    }

    public boolean endsWith(byte[] data) {
        if (getLength() < data.length) {
            return false;
        }

        for (int i = 0, j = getLength() - data.length; i < data.length; ++i, ++j) {
            if (data[i] != get(j)) {
                return false;
            }
        }

        return true;
    }

    public int indexOf(byte value) {
        for (int i = 0; i < this.buffer.length; ++i) {
            if (value == this.buffer[i]) {
                return i;
            }
        }

        return -1;
    }

    public int lastIndexOf(byte value) {
        int beginIndex = this.buffer.length - 1;

        for (int i = beginIndex; i >= beginIndex; --i) {
            if (value == this.buffer[i]) {
                return i;
            }
        }

        return -1;
    }

    public void delete(int startIndex) {
        this.index = startIndex;
    }

    public void delete(int startIndex, int endIndex) {
        System.arraycopy(this.buffer, endIndex, this.buffer, startIndex, this.index - endIndex);
        this.index -= endIndex - startIndex;
    }

    public void reverse() {
        for (int i = 0, j = this.index - 1; i < j; ++i, --j) {
            byte tmp = this.buffer[i];
            this.buffer[i] = this.buffer[j];
            this.buffer[j] = tmp;
        }
    }

    public void reset() {
        this.index = 0;
    }

    public byte[] toByteArray(int offset, int length) {
        byte[] ret = new byte[length];
        System.arraycopy(this.buffer, offset, ret, 0, ret.length);
        return ret;
    }

    public byte[] toByteArray() {
        return toByteArray(0, this.index);
    }

    public String toString(int offset, int len, Charset charset) {
        return new String(this.buffer, offset, len, charset);
    }

    public String toString(int offset, Charset charset) {
        return toString(offset, getLength() - offset, charset);
    }

    public String toString(Charset charset) {
        return toString(0, getLength(), charset);
    }

}
