/
ScryMUD/mud/
ScryMUD/mud/grrmud/Boards/
ScryMUD/mud/grrmud/Help/
ScryMUD/mud/grrmud/Pfiles/
ScryMUD/mud/grrmud/PlayerSacks/
ScryMUD/mud/grrmud/PlayerShops/
ScryMUD/mud/grrmud/help_filter/
ScryMUD/mud/hegemon/
ScryMUD/mud/hegemon/data/
ScryMUD/mud/hegemon/data/help/battle/
ScryMUD/mud/hegemon/data/help/client/
ScryMUD/mud/hegemon/data/help/communications/
ScryMUD/mud/hegemon/data/help/skills/
ScryMUD/mud/hegemon/data/help/spells/
ScryMUD/mud/include/
ScryMUD/mud/lib/
ScryMUD/mud/lib/bitfield/
ScryMUD/mud/lib/log/
ScryMUD/mud/lib/string2/
// $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