package org.free.bacnet4j.util;
import java.io.*;
import java.nio.charset.Charset;
public class ByteQueue implements Cloneable {
private byte queue[];
private int head;
private int tail;
private int size;
private int markHead;
private int markTail;
private int markSize;
public ByteQueue(){
this(1024);
}
public ByteQueue(int initialLength){
head = -1;
tail = 0;
size = 0;
queue = new byte[initialLength];
}
public ByteQueue(byte b[]){
this(b.length);
push(b, 0, b.length);
}
public ByteQueue(byte b[], int pos, int length){
this(length);
push(b, pos, length);
}
public void push(byte b){
if(room() == 0)
expand();
queue[tail] = b;
if(head == -1)
head = 0;
tail = (tail + 1) % queue.length;
size++;
}
public void push(int i){
push((byte)i);
}
public void push(long l){
push((byte)(int)l);
}
public void pushU2B(int i){
push((byte)(i >> 8));
push((byte)i);
}
public void pushU3B(int i){
push((byte)(i >> 16));
push((byte)(i >> 8));
push((byte)i);
}
public void pushS4B(int i){
pushInt(i);
}
public void pushU4B(long l){
push((byte)(int)(l >> 24));
push((byte)(int)(l >> 16));
push((byte)(int)(l >> 8));
push((byte)(int)l);
}
public void pushChar(char c){
push((byte)(c >> 8));
push((byte)c);
}
public void pushDouble(double d){
pushLong(Double.doubleToLongBits(d));
}
public void pushFloat(float f){
pushInt(Float.floatToIntBits(f));
}
public void pushInt(int i){
push((byte)(i >> 24));
push((byte)(i >> 16));
push((byte)(i >> 8));
push((byte)i);
}
public void pushLong(long l){
push((byte)(int)(l >> 56));
push((byte)(int)(l >> 48));
push((byte)(int)(l >> 40));
push((byte)(int)(l >> 32));
push((byte)(int)(l >> 24));
push((byte)(int)(l >> 16));
push((byte)(int)(l >> 8));
push((byte)(int)l);
}
public void pushShort(short s){
push((byte)(s >> 8));
push((byte)s);
}
public void read(InputStream in, int length) throws IOException{
if(length == 0)
return;
for(; room() < length; expand());
int tailLength = queue.length - tail;
if(tailLength > length)
readImpl(in, tail, length);
else
readImpl(in, tail, tailLength);
if(length > tailLength)
readImpl(in, 0, length - tailLength);
if(head == -1)
head = 0;
tail = (tail + length) % queue.length;
size += length;
}
private void readImpl(InputStream in, int offset, int length) throws IOException{
int readcount;
for(; length > 0; length -= readcount){
readcount = in.read(queue, offset, length);
offset += readcount;
}
}
public void push(byte b[]){
push(b, 0, b.length);
}
public void push(byte b[], int pos, int length){
if(length == 0)
return;
for(; room() < length; expand());
int tailLength = queue.length - tail;
if(tailLength > length)
System.arraycopy(b, pos, queue, tail, length);
else
System.arraycopy(b, pos, queue, tail, tailLength);
if(length > tailLength)
System.arraycopy(b, tailLength + pos, queue, 0, length - tailLength);
if(head == -1)
head = 0;
tail = (tail + length) % queue.length;
size += length;
}
public void push(ByteQueue source){
if(source.size == 0)
return;
if(source == this)
source = (ByteQueue)clone();
int firstCopyLen = source.queue.length - source.head;
if(source.size < firstCopyLen)
firstCopyLen = source.size;
push(source.queue, source.head, firstCopyLen);
if(firstCopyLen < source.size)
push(source.queue, 0, source.tail);
}
public void mark(){
markHead = head;
markTail = tail;
markSize = size;
}
public void reset(){
head = markHead;
tail = markTail;
size = markSize;
}
public byte pop(){
byte retval = queue[head];
if(size == 1){
head = -1;
tail = 0;
} else{
head = (head + 1) % queue.length;
}
size--;
return retval;
}
public int popU1B(){
return pop() & 0xff;
}
public int popU2B(){
return (pop() & 0xff) << 8 | pop() & 0xff;
}
public int popU3B(){
return (pop() & 0xff) << 16 | (pop() & 0xff) << 8 | pop() & 0xff;
}
public int popS4B(){
return (pop() & 0xff) << 24 | (pop() & 0xff) << 16 | (pop() & 0xff) << 8 | pop() & 0xff;
}
public long popU4B(){
return (long)(pop() & 0xff) << 24 | (long)(pop() & 0xff) << 16 | (long)(pop() & 0xff) << 8 | (long)(pop() & 0xff);
}
public int pop(byte buf[]){
return pop(buf, 0, buf.length);
}
public int pop(byte buf[], int pos, int length){
length = peek(buf, pos, length);
size -= length;
if(size == 0){
head = -1;
tail = 0;
} else{
head = (head + length) % queue.length;
}
return length;
}
public int pop(int length){
if(length == 0)
return 0;
if(size == 0)
throw new ArrayIndexOutOfBoundsException(-1);
if(length > size)
length = size;
size -= length;
if(size == 0){
head = -1;
tail = 0;
} else{
head = (head + length) % queue.length;
}
return length;
}
public String popString(int length, Charset charset){
byte b[] = new byte[length];
pop(b);
return new String(b, charset);
}
public byte[] popAll(){
byte data[] = new byte[size];
pop(data, 0, data.length);
return data;
}
public void write(OutputStream out) throws IOException {
write(out, size);
}
public void write(OutputStream out, int length) throws IOException {
if(length == 0)
return;
if(size == 0)
throw new ArrayIndexOutOfBoundsException(-1);
if(length > size)
length = size;
int firstCopyLen = queue.length - head;
if(length < firstCopyLen)
firstCopyLen = length;
out.write(queue, head, firstCopyLen);
if(firstCopyLen < length)
out.write(queue, 0, length - firstCopyLen);
size -= length;
if(size == 0){
head = -1;
tail = 0;
} else{
head = (head + length) % queue.length;
}
}
public byte tailPop(){
if(size == 0)
throw new ArrayIndexOutOfBoundsException(-1);
tail = ((tail + queue.length) - 1) % queue.length;
byte retval = queue[tail];
if(size == 1){
head = -1;
tail = 0;
}
size--;
return retval;
}
public byte peek(int index){
if(index >= size){
throw new IllegalArgumentException((new StringBuilder()).append("index ").append(index).append(" is >= queue size ").append(size).toString());
} else{
index = (index + head) % queue.length;
return queue[index];
}
}
public byte[] peek(int index, int length){
byte result[] = new byte[length];
for(int i = 0; i < length; i++)
result[i] = peek(index + i);
return result;
}
public byte[] peekAll(){
byte data[] = new byte[size];
peek(data, 0, data.length);
return data;
}
public int peek(byte buf[]){
return peek(buf, 0, buf.length);
}
public int peek(byte buf[], int pos, int length){
if(length == 0)
return 0;
if(size == 0)
throw new ArrayIndexOutOfBoundsException(-1);
if(length > size)
length = size;
int firstCopyLen = queue.length - head;
if(length < firstCopyLen)
firstCopyLen = length;
System.arraycopy(queue, head, buf, pos, firstCopyLen);
if(firstCopyLen < length)
System.arraycopy(queue, 0, buf, pos + firstCopyLen, length - firstCopyLen);
return length;
}
public int indexOf(byte b){
return indexOf(b, 0);
}
public int indexOf(byte b, int start){
if(start >= size)
return -1;
int index = (head + start) % queue.length;
for(int i = start; i < size; i++){
if(queue[index] == b)
return i;
index = (index + 1) % queue.length;
}
return -1;
}
public int indexOf(byte b[]){
return indexOf(b, 0);
}
public int indexOf(byte b[], int start){
if(b == null || b.length == 0)
throw new IllegalArgumentException("cannot search for empty values");
for(; (start = indexOf(b[0], start)) != -1 && start < (size - b.length) + 1; start++){
boolean found = true;
int i = 1;
do{
if(i >= b.length)
break;
if(peek(start + i) != b[i])
{
found = false;
break;
}
i++;
} while(true);
if(found)
return start;
}
return -1;
}
public int size(){
return size;
}
public void clear(){
size = 0;
head = -1;
tail = 0;
}
private int room(){
return queue.length - size;
}
private void expand(){
byte newb[] = new byte[queue.length * 2];
if(head == -1){
queue = newb;
return;
}
if(tail > head){
System.arraycopy(queue, head, newb, head, tail - head);
queue = newb;
return;
} else{
System.arraycopy(queue, head, newb, head + queue.length, queue.length - head);
System.arraycopy(queue, 0, newb, 0, tail);
head += queue.length;
queue = newb;
return;
}
}
public Object clone(){
try{
ByteQueue clone = (ByteQueue)super.clone();
clone.queue = (byte[])queue.clone();
return clone;
}
catch(CloneNotSupportedException e){
return null;
}
}
public String toString(){
if(size == 0)
return "[]";
StringBuffer sb = new StringBuffer();
sb.append('[');
sb.append(Integer.toHexString(peek(0) & 0xff));
for(int i = 1; i < size; i++)
sb.append(',').append(Integer.toHexString(peek(i) & 0xff));
sb.append("]");
return sb.toString();
}
public String dumpQueue(){
StringBuffer sb = new StringBuffer();
if(queue.length == 0){
sb.append("[]");
} else{
sb.append('[');
sb.append(queue[0]);
for(int i = 1; i < queue.length; i++){
sb.append(", ");
sb.append(queue[i]);
}
sb.append("]");
}
sb.append(", h=").append(head).append(", t=").append(tail).append(", s=").append(size);
return sb.toString();
}
}