// $Id: ScrollComponentQueue.java,v 1.3 1999/06/05 23:29:12 greear Exp $
// $Revision: 1.3 $ $Author: greear $ $Date: 1999/06/05 23:29:12 $
//
//Hegemon Client Code: Java Client for ScryMUD Server Code
//Copyright (C) 1998 Ben Greear
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// To contact the Author, Ben Greear: greear@cyberhighway.net, (preferred)
// greearb@agcs.com
//
import java.util.*;
/** Head points to the next slot to add an element to.
Tail points to the slot just before oldest element.
If (previous index of head) == tail, then the queue is empty.
NOTE: this queue wastes one space, but this gives us a lot
more simplicity in keeping track of is-full and is_empty status.
*/
class ScrollComponentQueue implements ScrollComponentCollection {
int head_idx;
int tail_idx;
int len;
ScrollComponent[] vect;
int total_height;
int item_count;
public ScrollComponentQueue(int length) {
super();
len = length + 1; /* we waste a space for simplicity */
head_idx = 0;
tail_idx = len - 1;
vect = new ScrollComponent[len];
total_height = 0;
item_count = 0;
}//constructor
public void clear() {
head_idx = 0;
tail_idx = len - 1;
//vect = new ScrollComponent[len];
item_count = total_height = 0;
}//clear
public String toString() {
return ("ScrollComponentQueue: height: " + total_height);
}
public int getTotalHeight() {
return total_height;
}
//TODO: make this more efficient
/** This gives us the index of the first element we want to add to our
Vector when getting a 'page'. It could be speeded up with some sort
of caching scheme I think.. */
private final int findFirst(int y_top) {
int my_idx = getNextIdx(tail_idx);
int sofar = 0;
ScrollComponent sc;
while (true) {
//if we're all the way to the end
if (my_idx == head_idx)
return my_idx;
sc = (vect[my_idx]);
if (sc != null) {
sofar += sc.getHeight();
}
//if we've encountered it alreaady
if (sofar >= y_top)
return my_idx;
my_idx = getNextIdx(my_idx);
}//while
}//findFirst
/** This is the common case for screen draws. */
public final synchronized Vector getBottomPage(int total_height) {
Vector tmp_retval = new Vector(100);
if (isEmpty())
return tmp_retval;
int my_idx = getPrevIdx(head_idx);
int default_last = getNextIdx(tail_idx);
int height_sofar = 0;
ScrollComponent sc;
// Log.it("getBottomPage: my_idx: " + my_idx + " default_last: "
// + default_last + " total_height: " + total_height);
while (true) {
if (my_idx == default_last) {
//Log.it("Found default_last, NULL count: " + cnt);
break;
}
sc = vect[my_idx];
if (sc != null) {
height_sofar += sc.getHeight();
tmp_retval.addElement(sc);
}
else {
Log.instance().err("ERROR: sc is NULL, idx: " + my_idx);
}
if (height_sofar >= total_height) {
//Log.it("Height satisfied, NULL count: " + cnt);
break;
}
my_idx = getPrevIdx(my_idx);
}//while
/* when here, we have the return value, but it is reversed. */
/* we need to reverse the reversed one to return a correct Vector. */
int sz = tmp_retval.size();
Vector retval = new Vector(sz);
for (int i = sz - 1; i >= 0; i--) {
retval.addElement(tmp_retval.elementAt(i));
}
return retval;
}//getBottomPage
/** Return an array of Objects contained in the queue. The
oldest elements are at the lower indexes of the returned
array.. */
public final synchronized Vector getVector(int y_top, int y_bottom) {
//Log.it("ScrollComponentQueue.getVector: y_top: " + y_top
// + " y_bottom: " + y_bottom + " tail: " + tail_idx
// + " head: " + head_idx);
Vector retval = new Vector(100);
if (isEmpty())
return retval;
int my_idx = this.findFirst(y_top);
int default_last = getPrevIdx(head_idx);
int total_height = y_bottom - y_top;
int height_sofar = 0;
ScrollComponent sc;
//Log.it("ScrollComponentQueue.getVector: my_idx: " + my_idx
// + " default_last: " + default_last
// + " total_height: " + total_height);
while (true) {
if (my_idx == default_last) {
//Log.it("Fount default_last, NULL count: " + cnt);
return retval;
}
sc = vect[my_idx];
if (sc != null) {
height_sofar += sc.getHeight();
retval.addElement(sc);
}
else {
Log.instance().err("ERROR: getVector(), sc is NULL, idx: " + my_idx);
}
if (height_sofar >= total_height) {
//Log.it("Height satisfied, NULL count: " + cnt);
return retval;
}
my_idx = getNextIdx(my_idx);
}//while
}//getArray
/** Add an object to the head of the queue, will throw an
Exception if its already full. */
public final synchronized void push(ScrollComponent obj) {
//Log.it("ScrollComponentQueue: in push");//, obj: " + obj);
if (this.isFull()) {
try {
this.pull();
}
catch (Exception e) {
Log.instance().err(toString() + e);
}
}
vect[head_idx] = obj;
head_idx = getNextIdx(head_idx);
total_height += obj.getHeight();
item_count++;
}//push
/** Remove and return the oldest object from the queue. Throws
Exception if it's empty. */
public final synchronized Object pull() throws Exception {
if (!isEmpty()) {
tail_idx = getNextIdx(tail_idx);
ScrollComponent sc = vect[tail_idx];
total_height -= sc.getHeight();
vect[tail_idx] = null;
item_count--;
return sc;
}
else {
throw new Exception("ERROR: ScrollComponentQueue.pull: Queue"
+ " is empty.");
}
}//pull
/** returns the oldest object, but DOES NOT REMOVE IT
from the queue. Throws exception if its empty. */
public final synchronized Object peek() throws Exception {
if (!isEmpty()) {
return vect[getNextIdx(tail_idx)];
}
else {
throw new Exception("ERROR: on peek(), Queue is empty.");
}
}//pull
private final int getNextIdx(int idx) {
if (idx == (len - 1)) {
return 0;
}
else {
return idx + 1;
}
}//getNextIdx
private final int getPrevIdx(int idx) {
if (idx == 0)
return len - 1;
else
return idx - 1;
}//getPrevIdx
/** Test the empty-ness of the queue. */
public final boolean isEmpty() {
if (getPrevIdx(head_idx) == tail_idx)
return true;
else
return false;
}//isEmpty
/** Test the fullness of the queue. */
public final boolean isFull() {
if (tail_idx == head_idx)
return true;
else
return false;
}//is Full
/** Return the number of elements found in the queue. Could
allow for a cheaper method of cleaning out the array (ie don't have
to test for isEmpty all the time..) */
public final int length() {
return item_count;
}//length
public final int capacity() {
return len - 1;
}
}//ScrollComponentQueue