/*
   D-Bus Java Implementation
   Copyright (c) 2005-2006 Matthew Johnson

   This program is free software; you can redistribute it and/or modify it
   under the terms of either the GNU Lesser General Public License Version 2 or the
   Academic Free Licence Version 2.1.

   Full licence texts are included in the COPYING file with this program.
*/
package org.freedesktop.dbus;

import cx.ath.matthew.debug.Debug;

/**
 * Provides a Message queue which doesn't allocate objects
 * on insertion/removal. */
class EfficientQueue
{
   private Message[] mv;
   private int start;
   private int end;
   private int init_size;
   public EfficientQueue(int initial_size)
   {
      init_size = initial_size;
      shrink();
   }
   private void grow()
   {
      if (Debug.debug) Debug.print(Debug.DEBUG, "Growing");
      // create new vectors twice as long
      Message[] oldmv = mv;
      mv = new Message[oldmv.length*2];

      // copy start->length to the start of the new vector
      System.arraycopy(oldmv,start,mv,0,oldmv.length-start);
      // copy 0->end to the next part of the new vector
      if (end != (oldmv.length-1)) {
         System.arraycopy(oldmv,0,mv,oldmv.length-start,end+1);
      }
      // reposition pointers
      start = 0;
      end = oldmv.length;
   }
   // create a new vector with just the valid keys in and return it
   public Message[] getKeys()
   {
      if (start == end) return new Message[0];
      Message[] lv;
      if (start < end) {
         int size = end-start;
         lv = new Message[size];
         System.arraycopy(mv, start, lv, 0, size);
      } else {
         int size = mv.length-start+end;
         lv = new Message[size];
         System.arraycopy(mv, start, lv, 0, mv.length-start);
         System.arraycopy(mv, 0, lv, mv.length-start, end);
      }
      return lv;
   }
   private void shrink()
   {
      if (Debug.debug) Debug.print(Debug.DEBUG, "Shrinking");
      if (null != mv && mv.length == init_size) return;
      // reset to original size
      mv = new Message[init_size];
      start = 0;
      end = 0;
   }
   public void add(Message m)
   {
      if (Debug.debug) Debug.print(Debug.DEBUG, "Enqueueing Message "+m);
      // put this at the end
      mv[end] = m;
      // move the end
      if (end == (mv.length-1)) end = 0; else end++;
      // if we are out of space, grow.
      if (end == start) grow();
   }
   public Message remove()
   {
      if (start == end) return null;
      // find the item
      int pos = start;
      // get the value
      Message m = mv[pos];
      // set it as unused
      mv[pos] = null;
      if (start == (mv.length-1)) start = 0; else start++;
      if (Debug.debug) Debug.print(Debug.DEBUG, "Dequeueing "+m);
      return m;
   }
   public boolean isEmpty()
   {
      // check if find succeeds
      return start == end;
   }   
   public int size()
   {
      if (end >= start)
         return end-start;
      else
         return mv.length-start+end;
   }
}
