/*
 * 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 org.jboss.cache.Fqn;
import org.jboss.cache.aop.AOPInstance;
import org.jboss.cache.aop.TreeCacheAop;

import java.util.Iterator;
import java.util.Set;


/** Provider to provide eviction policy. This one is based on LRU algorithm that a user
 * can specify either maximum number of nodes or the idle time of a node to be evicted.
 *
 * @author Ben Wang 02-2004
 */
public class AopLRUPolicy extends LRUPolicy  implements AopEvictionPolicy
{
   public AopLRUPolicy() {
      super();
   }

   /**
    * Override for aop-specific. In this case, if a node is visited and it is an aop-node, i.e.,
    * it has AopInstance, then all the children nodes are considered visited as well.
    * @param fqn
    */
   public void nodeVisited(Fqn fqn)
   {
      if(isInternalNode(fqn)) return;

      Region region = regionManager_.getRegion(fqn.toString());
      // TODO May need to optimize to check if this fqn is already on the queue. No need to process it twice.
      region.setVisitedNode(fqn);

      if(!isAopNode(fqn))
         return;


      visitChildrenRecursively(region, fqn);
   }

   protected void visitChildrenRecursively(Region region, Fqn fqn) {
      Set set = getChildrenNames(fqn);
      int size = (set == null) ? 0: set.size();
      if(log_.isTraceEnabled()) {
         log_.trace("nodeVisited(): is an aop node. fqn- " +fqn + " size of children is " +size);
      }

      if(set == null) return; // barren
      Iterator it = set.iterator();
      while(it.hasNext()) {
         Object childName = it.next();
         Fqn fqnKid = new Fqn(fqn, childName);
         visitChildrenRecursively(region, fqnKid);
         region.setVisitedNode(fqnKid);
      }
   }

   private boolean isAopNode(Fqn fqn)
   {
      try {
         return (cache_.peek(fqn, AOPInstance.KEY) != null) ? true: false;
      } catch (Exception e) {
         log_.warn("isAopNode(): cache get operation generated exception " +e);
         return false;
      }
   }

   public void nodeAdded(Fqn fqn)
   {
      if(isInternalNode(fqn)) return;

      super.nodeAdded(fqn);
   }

   /**
    * Note that this removes all children nodes as well. So we will need to put the children nodes
    * into removed queue.
    * @param fqn
    */
   public void nodeRemoved(Fqn fqn)
   {
      if(isInternalNode(fqn)) return;

      super.nodeRemoved(fqn);
   }

   public void nodeModified(Fqn fqn) {
      super.nodeModified(fqn);
   }

   // we are using the same eviction algorithm now.
   protected EvictionAlgorithm getEvictionAlgorithm() {
      return new LRUAlgorithm();
   }

   /**
    * Check if this is an JBossInternal node. If it is, no need to proceed since we don't
    * care about it.
    * @param fqn
    * @return
    */
   protected boolean isInternalNode(Fqn fqn) {
      String startStr = (String)fqn.get(0);
      if( startStr.equals(TreeCacheAop.JBOSS_INTERNAL.get(0))) return true;

      return false;
   }
}