// Automatically translated by XLang.py to Java from cbx.h.
/// SinkWorld split buffer class
/// Copyright 2001 Neil Hodgson
/// All implementations use the intrinsic char type which is 1 byte
/// in C++ and 2 bytes in Java and C#.

class cbx {
        
char[] body;
        
int size;
        
int length;
        
int part1Length;
        
int gapLength;
        
int growSize;

        
/// Move the gap to a particular position so that insertion and
        
/// deletion at that point will not require much copying and
        
/// hence be fast.
        
private void GapTo(int position) {
                
if (position != part1Length) {
                        
if (position < part1Length) {
                                
int diff = part1Length - position;
                                
for (int i = 0; i < diff; i++)
                                        
body[part1Length + gapLength - i - 1] =
                                                
body[part1Length - i - 1];
                        
} else { // position > part1Length
                                
int diff = position - part1Length;
                                
for (int i = 0; i < diff; i++)
                                        
body[part1Length + i] =
                                                
body[part1Length + gapLength + i];
                        
}
                        
part1Length = position;
                
}
        
}

        
/// Reallocate the storage for the buffer to be newSize and
        
/// copy exisiting contents to the new buffer.
        
/// Must not be used to decrease the size of the buffer.
        
private void ReAllocate(int newSize) {
                
// Move the gap to the end
                
GapTo(length);
                
char[] newBody = new char[newSize];
                
if (size != 0) {
                        
for (int i = 0; i < size; i++)
                                
newBody[i] = body[i];
                        
// delete []body;
                
}
                
body = newBody;
                
gapLength += newSize - size;
                
size = newSize;
        
}

        
/// Check that there is room in the buffer for an insertion,
        
/// reallocating if more space needed.
        
private void RoomFor(int insertionLength) {
                
if (gapLength <= insertionLength) {
                        
if (growSize * 6 < size)
                                
growSize *= 2;
                        
ReAllocate(size + insertionLength + growSize);
                
}
        
}

        
/// Construct a split buffer.
        
public cbx(int initialLength, int growSize_) {
                
growSize = growSize_;
                
size = 0;
                
length = 0;
                
part1Length = 0;
                
gapLength = 0;
                
ReAllocate(initialLength);
        
}

        
/// Retrieve the character at a particular position.
        
/// Retrieving positions outside the range of the buffer works
        
/// and returns 0.
        
public char CharAt(int position) {
                
if (position < part1Length) {
                        
if (position < 0) {
                                
return '\0';
                        
} else {
                                
return body[position];
                        
}
                
} else {
                        
if (position >= length) {
                                
return '\0';
                        
} else {
                                
return body[gapLength + position];
                        
}
                
}
        
}

        
/// Retrieve the length of the buffer.
        
public int Length() {
                
return length;
        
}

        
/// Retrieve a range of text from the buffer.
        
/// Retrieving positions outside the range of the buffer fails.
        
public void RetrieveString(int position, char[] s, int retrieveLength) {
                
int i = 0;
                
int pos = position;
                
while ((i < retrieveLength) && (pos < part1Length)) {
                        
s[i++] = body[pos++];
                
}
                
while (i < retrieveLength) {
                        
s[i++] = body[gapLength + pos++];
                
}
        
}

        
/// Insert text into the buffer.
        
/// Inserting at positions outside the current range throws a
        
/// BadPositionException.
        
public void InsertString(int position, char[] s, int insertLength) {
                
if (insertLength > 0) {
                        
if ((position < 0) || (position > length)) {
                                
throw new BadPositionException();
                        
}
                        
RoomFor(insertLength);
                        
GapTo(position);
                        
for (int i = 0; i < insertLength; i++)
                                
body[part1Length + i] = s[i];
                        
length += insertLength;
                        
part1Length += insertLength;
                        
gapLength -= insertLength;
                
}
        
}

        
/// Fill an already allocated range with a value.
        
/// Modifying outside the current range throws a
        
/// BadPositionException.
        
public void FillRange(int position, char ch, int fillLength) {
                
if (fillLength > 0) {
                        
if ((position < 0) || ((position + fillLength) > length)) {
                                
throw new BadPositionException();
                        
}
                        
int i = 0;
                        
int pos = position;
                        
while ((i < fillLength) && (pos < part1Length)) {
                                
body[pos++] = ch;
                                
i++;
                        
}
                        
while (i < fillLength) {
                                
body[gapLength + pos++] = ch;
                                
i++;
                        
}
                
}
        
}

        
/// Insert a number of zero characters into the buffer.
        
/// Inserting at positions outside the current range fails.
        
public void InsertZeros(int position, int insertLength) {
                
if (insertLength > 0) {
                        
RoomFor(insertLength);
                        
GapTo(position);
                        
for (int i = 0; i < insertLength; i++)
                                
body[part1Length + i] = '\0';
                        
length += insertLength;
                        
part1Length += insertLength;
                        
gapLength -= insertLength;
                
}
        
}

        
/// Delete a range from the buffer.
        
/// Deleting positions outside the current range fails.
        
public void DeleteChars(int position, int deleteLength) {
                
if (deleteLength > 0) {
                        
GapTo(position);
                        
length -= deleteLength;
                        
gapLength += deleteLength;
                
}
        
}
};