/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 * Created on March 25 2003
 */
package org.jboss.cache.eviction;

import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
import org.jboss.cache.Fqn;
import org.jboss.logging.Logger;

/**
 * A region is a collection of tree cache nodes that share the same eviction
 * policy configurations, e.g., maxNodes, etc. The region is specified via
 * Fqn.
 *
 * @author Ben Wang 2-2004
 */
public class Region
{

   public static final long WAIT_TIME = 10000; // time to wait for the queue to free up

   // Policy-specific config
   private int maxNodes_ = 0; // 0 is no limit
   private long timeToLiveSeconds_ = 0; // 0 is forever
   // Region name
   private String fqn_;
   // Policy-spefic algorithm, e.g., LRU
   private EvictionAlgorithm algorithm_;
   // Parent policy provider
   private EvictionPolicy policy_;
   // These queues can do put and take concurrently.
   protected BoundedBuffer nodeEventQueue_;
   protected Logger log_ = Logger.getLogger(Region.class);

   /**
    * Default to package namespace on purpose so no one outside the package can instantiate it,
    */
   Region()
   {
      createQueue();
   }

   void createQueue()
   {
      nodeEventQueue_ = new BoundedBuffer(RegionManager.CAPACITY);
   }

   Region(String fqn, EvictionPolicy policy, EvictionAlgorithm algorithm) {
      fqn_ = fqn;
      policy_ = policy;
      algorithm_ = algorithm;

      createQueue();
   }

   public int getMaxNodes() { return maxNodes_; }

   public void setMaxNodes(int maxNodes) { maxNodes_ = maxNodes; }

//   public long getTimeToIdleSeconds() { return timeToLiveSeconds_; }

//   public void setTimeToIdleSeconds(long secs) { timeToLiveSeconds_ = secs; }

   public long getTimeToLiveSeconds() { return timeToLiveSeconds_; }

   public void setTimeToLiveSeconds(long secs) { timeToLiveSeconds_ = secs; }

   public EvictionAlgorithm getEvictionAlgorithm() { return algorithm_; }

   public EvictionPolicy getEvictionPolicy() { return policy_; }

   public String getFqn() { return fqn_; }

   public void setAddedNode(Fqn fqn)
   {
      putNodeEvent(fqn, EvictedEventNode.ADD_EVENT);
   }

   public void setRemovedNode(Fqn fqn)
   {
      putNodeEvent(fqn, EvictedEventNode.REMOVE_EVENT);
   }

   public void setVisitedNode(Fqn fqn)
   {
      putNodeEvent(fqn, EvictedEventNode.VISIT_EVENT);
   }

   protected void putNodeEvent(Fqn fqn, Integer event) {
      try {
//         if(!nodeQueue_.offer(fqn, WAIT_TIME)) return;
         if( nodeEventQueue_.size() > (100*RegionManager.CAPACITY)/98 ) {
            log_.warn("putNodeEvent(): eviction node event queue size is at 98% threshold value of capacity: "
                  +RegionManager.CAPACITY + " You will need to reduce the wakeUpIntervalSeconds parameter.");
         }
         nodeEventQueue_.put(new EvictedEventNode(fqn, event));
      } catch (InterruptedException e) {
         e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
   }

   /**
    * Take the last node from node queue. It will also
    * remove it from the queue.
    * @return
    */
   public EvictedEventNode takeLastEventNode()
   {
      try {
         return (EvictedEventNode)nodeEventQueue_.poll(0);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
      return null;
   }

   public int nodeEventQueueSize()
   {
      return nodeEventQueue_.size();
   }

   public void resetEvictionQueues()
   {
      BoundedBuffer q1 = nodeEventQueue_;
      log_.info("reseteEvictionQueues(): node queue size: " +q1.size() +
              " region name: " +fqn_);
      createQueue();
      // Help to recycle
      for(int i=0; i < q1.size(); i++) {
         try {
            q1.take();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }

   public String toString() {
      StringBuffer buf = new StringBuffer();
      buf.append("Regions--- fqn: ").append(getFqn()).append(" maxNodes " +getMaxNodes());
      buf.append(" TimeToIdleSeconds " +getTimeToLiveSeconds());
      return buf.toString();
   }
}